Changeset 35285 in webkit for trunk/JavaScriptCore/kjs/JSArray.cpp
- Timestamp:
- Jul 22, 2008, 7:26:01 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/JSArray.cpp
r35203 r35285 28 28 #include <wtf/AVLTree.h> 29 29 #include <wtf/Assertions.h> 30 #include <operations.h> 30 31 31 32 #define CHECK_ARRAY_CONSISTENCY 0 … … 35 36 namespace KJS { 36 37 38 // Overview of JSArray 39 // 40 // Properties of JSArray objects may be stored in one of three locations: 41 // * The regular JSObject property map. 42 // * A storage vector. 43 // * A sparse map of array entries. 44 // 45 // Properties with non-numeric identifiers, with identifiers that are not representable 46 // as an unsigned integer, or where the value is greater than MAX_ARRAY_INDEX 47 // (specifically, this is only one property - the value 0xFFFFFFFFU as an unsigned 32-bit 48 // integer) are not considered array indices and will be stored in the JSObject property map. 49 // 50 // All properties with a numeric identifer, representable as an unsigned integer i, 51 // where (i <= MAX_ARRAY_INDEX), are an array index and will be stored in either the 52 // storage vector or the sparse map. An array index i will be handled in the following 53 // fashion: 54 // 55 // * Where (i < MIN_SPARSE_ARRAY_INDEX) the value will be stored in the storage vector. 56 // * Where (MIN_SPARSE_ARRAY_INDEX <= i <= MAX_STORAGE_VECTOR_INDEX) the value will either 57 // be stored in the storage vector or in the sparse array, depending on the density of 58 // data that would be stored in the vector (a vector being used where at least 59 // (1 / minDensityMultiplier) of the entries would be populated). 60 // * Where (MAX_STORAGE_VECTOR_INDEX < i <= MAX_ARRAY_INDEX) the value will always be stored 61 // in the sparse array. 62 63 // The definition of MAX_STORAGE_VECTOR_LENGTH is dependant on the definition storageSize 64 // function below - the MAX_STORAGE_VECTOR_LENGTH limit is defined such that the storage 65 // size calculation cannot overflow. (sizeof(ArrayStorage) - sizeof(JSValue*)) + 66 // (vectorLength * sizeof(JSValue*)) must be <= 0xFFFFFFFFU (which is maximum value of size_t). 67 #define MAX_STORAGE_VECTOR_LENGTH static_cast<unsigned>((0xFFFFFFFFU - (sizeof(ArrayStorage) - sizeof(JSValue*))) / sizeof(JSValue*)) 68 69 // These values have to be macros to be used in max() and min() without introducing 70 // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>. 71 #define MIN_SPARSE_ARRAY_INDEX 10000U 72 #define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1) 37 73 // 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer. 38 static const unsigned maxArrayIndex = 0xFFFFFFFEU; 74 #define MAX_ARRAY_INDEX 0xFFFFFFFEU 39 75 40 76 // Our policy for when to use a vector and when to use a sparse map. 41 // For all array indices under sparseArrayCutoff, we always use a vector.42 // When indices greater than sparseArrayCutoffare involved, we use a vector77 // For all array indices under MIN_SPARSE_ARRAY_INDEX, we always use a vector. 78 // When indices greater than MIN_SPARSE_ARRAY_INDEX are involved, we use a vector 43 79 // as long as it is 1/8 full. If more sparse than that, we use a map. 44 // This value has to be a macro to be used in max() and min() without introducing45 // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.46 #define sparseArrayCutoff 10000U47 80 static const unsigned minDensityMultiplier = 8; 48 81 … … 51 84 static inline size_t storageSize(unsigned vectorLength) 52 85 { 53 return sizeof(ArrayStorage) - sizeof(JSValue*) + vectorLength * sizeof(JSValue*); 86 ASSERT(vectorLength <= MAX_STORAGE_VECTOR_LENGTH); 87 88 // MAX_STORAGE_VECTOR_LENGTH is defined such that provided (vectorLength <= MAX_STORAGE_VECTOR_LENGTH) 89 // - as asserted above - the following calculation cannot overflow. 90 size_t size = (sizeof(ArrayStorage) - sizeof(JSValue*)) + (vectorLength * sizeof(JSValue*)); 91 // Assertion to detect integer overflow in previous calculation (should not be possible, provided that 92 // MAX_STORAGE_VECTOR_LENGTH is correctly defined). 93 ASSERT(((size - (sizeof(ArrayStorage) - sizeof(JSValue*))) / sizeof(JSValue*) == vectorLength) && (size >= (sizeof(ArrayStorage) - sizeof(JSValue*)))); 94 95 return size; 54 96 } 55 97 56 98 static inline unsigned increasedVectorLength(unsigned newLength) 57 99 { 58 return (newLength * 3 + 1) / 2; 100 ASSERT(newLength <= MAX_STORAGE_VECTOR_LENGTH); 101 102 // Mathematically equivalent to: 103 // increasedLength = (newLength * 3 + 1) / 2; 104 // or: 105 // increasedLength = (unsigned)ceil(newLength * 1.5)); 106 // This form is not prone to internal overflow. 107 unsigned increasedLength = newLength + (newLength >> 1) + (newLength & 1); 108 ASSERT(increasedLength >= newLength); 109 110 return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH); 59 111 } 60 112 … … 75 127 : JSObject(prototype) 76 128 { 77 unsigned initialCapacity = min(initialLength, sparseArrayCutoff);129 unsigned initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX); 78 130 79 131 m_length = initialLength; … … 132 184 133 185 if (i >= m_length) { 134 if (i > maxArrayIndex)186 if (i > MAX_ARRAY_INDEX) 135 187 return getOwnPropertySlot(exec, Identifier::from(exec, i), slot); 136 188 return false; … … 144 196 } 145 197 } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) { 146 if (i >= sparseArrayCutoff) {198 if (i >= MIN_SPARSE_ARRAY_INDEX) { 147 199 SparseArrayValueMap::iterator it = map->find(i); 148 200 if (it != map->end()) { … … 199 251 200 252 unsigned length = m_length; 201 if (i >= length && i <= maxArrayIndex) {253 if (i >= length && i <= MAX_ARRAY_INDEX) { 202 254 length = i + 1; 203 255 m_length = length; … … 226 278 SparseArrayValueMap* map = storage->m_sparseValueMap; 227 279 228 if (i >= sparseArrayCutoff) {229 if (i > maxArrayIndex) {280 if (i >= MIN_SPARSE_ARRAY_INDEX) { 281 if (i > MAX_ARRAY_INDEX) { 230 282 put(exec, Identifier::from(exec, i), value); 231 283 return; … … 234 286 // We miss some cases where we could compact the storage, such as a large array that is being filled from the end 235 287 // (which will only be compacted as we reach indices that are less than cutoff) - but this makes the check much faster. 236 if ( !isDenseEnoughForVector(i + 1, storage->m_numValuesInVector + 1)) {288 if ((i > MAX_STORAGE_VECTOR_INDEX) || !isDenseEnoughForVector(i + 1, storage->m_numValuesInVector + 1)) { 237 289 if (!map) { 238 290 map = new SparseArrayValueMap; … … 247 299 // Fast case is when there is no sparse map, so we can increase the vector size without moving values from it. 248 300 if (!map || map->isEmpty()) { 249 increaseVectorLength(i + 1); 250 storage = m_storage; 251 ++storage->m_numValuesInVector; 252 storage->m_vector[i] = value; 253 checkConsistency(); 301 if (increaseVectorLength(i + 1)) { 302 storage = m_storage; 303 ++storage->m_numValuesInVector; 304 storage->m_vector[i] = value; 305 checkConsistency(); 306 } else 307 throwOutOfMemoryError(exec); 254 308 return; 255 309 } … … 258 312 unsigned newNumValuesInVector = storage->m_numValuesInVector + 1; 259 313 unsigned newVectorLength = increasedVectorLength(i + 1); 260 for (unsigned j = max(storage->m_vectorLength, sparseArrayCutoff); j < newVectorLength; ++j)314 for (unsigned j = max(storage->m_vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) 261 315 newNumValuesInVector += map->contains(j); 262 if (i >= sparseArrayCutoff)316 if (i >= MIN_SPARSE_ARRAY_INDEX) 263 317 newNumValuesInVector -= map->contains(i); 264 318 if (isDenseEnoughForVector(newVectorLength, newNumValuesInVector)) { 265 319 unsigned proposedNewNumValuesInVector = newNumValuesInVector; 266 while (true) { 320 // If newVectorLength is already the maximum - MAX_STORAGE_VECTOR_LENGTH - then do not attempt to grow any further. 321 while (newVectorLength < MAX_STORAGE_VECTOR_LENGTH) { 267 322 unsigned proposedNewVectorLength = increasedVectorLength(newVectorLength + 1); 268 for (unsigned j = max(newVectorLength, sparseArrayCutoff); j < proposedNewVectorLength; ++j)323 for (unsigned j = max(newVectorLength, MIN_SPARSE_ARRAY_INDEX); j < proposedNewVectorLength; ++j) 269 324 proposedNewNumValuesInVector += map->contains(j); 270 325 if (!isDenseEnoughForVector(proposedNewVectorLength, proposedNewNumValuesInVector)) … … 276 331 277 332 storage = static_cast<ArrayStorage*>(fastRealloc(storage, storageSize(newVectorLength))); 333 if (!storage) { 334 throwOutOfMemoryError(exec); 335 return; 336 } 278 337 279 338 unsigned vectorLength = storage->m_vectorLength; … … 281 340 for (unsigned j = vectorLength; j < newVectorLength; ++j) 282 341 storage->m_vector[j] = 0; 283 if (i > sparseArrayCutoff)342 if (i > MIN_SPARSE_ARRAY_INDEX) 284 343 map->remove(i); 285 344 } else { 286 for (unsigned j = vectorLength; j < max(vectorLength, sparseArrayCutoff); ++j)345 for (unsigned j = vectorLength; j < max(vectorLength, MIN_SPARSE_ARRAY_INDEX); ++j) 287 346 storage->m_vector[j] = 0; 288 for (unsigned j = max(vectorLength, sparseArrayCutoff); j < newVectorLength; ++j)347 for (unsigned j = max(vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) 289 348 storage->m_vector[j] = map->take(j); 290 349 } … … 334 393 335 394 if (SparseArrayValueMap* map = storage->m_sparseValueMap) { 336 if (i >= sparseArrayCutoff) {395 if (i >= MIN_SPARSE_ARRAY_INDEX) { 337 396 SparseArrayValueMap::iterator it = map->find(i); 338 397 if (it != map->end()) { … … 346 405 checkConsistency(); 347 406 348 if (i > maxArrayIndex)407 if (i > MAX_ARRAY_INDEX) 349 408 return deleteProperty(exec, Identifier::from(exec, i)); 350 409 … … 384 443 unsigned vectorLength = storage->m_vectorLength; 385 444 ASSERT(newLength > vectorLength); 445 ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX); 386 446 unsigned newVectorLength = increasedVectorLength(newLength); 387 447 … … 474 534 unsigned lengthNotIncludingUndefined = compactForSorting(); 475 535 if (m_storage->m_sparseValueMap) { 476 exec->setException(Error::create(exec, GeneralError, "Out of memory"));536 throwOutOfMemoryError(exec); 477 537 return; 478 538 } … … 488 548 Vector<ArrayQSortPair> values(lengthNotIncludingUndefined); 489 549 if (!values.begin()) { 490 exec->setException(Error::create(exec, GeneralError, "Out of memory"));550 throwOutOfMemoryError(exec); 491 551 return; 492 552 } … … 625 685 626 686 if (!tree.abstractor().m_nodes.begin()) { 627 exec->setException(Error::create(exec, GeneralError, "Out of memory"));687 throwOutOfMemoryError(exec); 628 688 return; 629 689 } … … 660 720 newUsedVectorLength += map->size(); 661 721 if (newUsedVectorLength > m_storage->m_vectorLength) { 662 if (!increaseVectorLength(newUsedVectorLength)) { 663 exec->setException(Error::create(exec, GeneralError, "Out of memory")); 722 // Check that it is possible to allocate an array large enough to hold all the entries. 723 if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) { 724 throwOutOfMemoryError(exec); 664 725 return; 665 726 } … … 734 795 newUsedVectorLength += map->size(); 735 796 if (newUsedVectorLength > storage->m_vectorLength) { 736 if (!increaseVectorLength(newUsedVectorLength)) 797 // Check that it is possible to allocate an array large enough to hold all the entries - if not, 798 // exception is thrown by caller. 799 if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) 737 800 return 0; 738 801 storage = m_storage; … … 802 865 ASSERT(index < m_length); 803 866 ASSERT(index >= m_storage->m_vectorLength); 804 ASSERT(index <= maxArrayIndex);867 ASSERT(index <= MAX_ARRAY_INDEX); 805 868 ASSERT(it->second); 806 869 if (type != DestructorConsistencyCheck)
Note:
See TracChangeset
for help on using the changeset viewer.