Changeset 64320 in webkit
- Timestamp:
- Jul 29, 2010 4:29:17 PM (14 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r64319 r64320 1 2010-07-29 Michael Saboff <msaboff@apple.com> 2 3 Reviewed by Gavin Barraclough. 4 5 Changed the handling for removing and adding elements at the front 6 of an array. The code now keeps a bias that indicates the amount of 7 JSValue sized holes are prior to the ArrayStorage block. This means 8 that shift operations are now memmove's of the header part of 9 the ArrayStorage and unshift operations are similar, but may require a 10 realloc first to create the space. Similar operations are performed 11 for special cases of splice and slice. 12 Also optimized the new Array(size) case so that we don't allocate and 13 initialize array elements until the JS code starts using elements. 14 The array growth code is slightly more aggressive for initial growth 15 based on size growth of any previous array. 16 17 * Configurations/JavaScriptCore.xcconfig: 18 * jit/JITPropertyAccess.cpp: 19 (JSC::JIT::emit_op_get_by_val): 20 (JSC::JIT::emit_op_put_by_val): 21 (JSC::JIT::privateCompilePatchGetArrayLength): 22 * jit/JITPropertyAccess32_64.cpp: 23 (JSC::JIT::emit_op_get_by_val): 24 (JSC::JIT::emit_op_put_by_val): 25 (JSC::JIT::privateCompilePatchGetArrayLength): 26 * runtime/ArrayPrototype.cpp: 27 (JSC::arrayProtoFuncShift): 28 (JSC::arrayProtoFuncSplice): 29 (JSC::arrayProtoFuncUnShift): 30 * runtime/JSArray.cpp: 31 (JSC::JSArray::JSArray): 32 (JSC::JSArray::~JSArray): 33 (JSC::JSArray::getOwnPropertySlot): 34 (JSC::JSArray::getOwnPropertyDescriptor): 35 (JSC::JSArray::put): 36 (JSC::JSArray::putSlowCase): 37 (JSC::JSArray::deleteProperty): 38 (JSC::JSArray::getOwnPropertyNames): 39 (JSC::JSArray::getNewVectorLength): 40 (JSC::JSArray::increaseVectorLength): 41 (JSC::JSArray::increaseVectorPrefixLength): 42 (JSC::JSArray::setLength): 43 (JSC::JSArray::pop): 44 (JSC::JSArray::push): 45 (JSC::JSArray::shiftCount): 46 (JSC::JSArray::unshiftCount): 47 (JSC::JSArray::sortNumeric): 48 (JSC::JSArray::sort): 49 (JSC::JSArray::fillArgList): 50 (JSC::JSArray::copyToRegisters): 51 (JSC::JSArray::compactForSorting): 52 (JSC::JSArray::subclassData): 53 (JSC::JSArray::setSubclassData): 54 (JSC::JSArray::checkConsistency): 55 * runtime/JSArray.h: 56 (JSC::JSArray::length): 57 (JSC::JSArray::canGetIndex): 58 (JSC::JSArray::getIndex): 59 (JSC::JSArray::setIndex): 60 (JSC::JSArray::uncheckedSetIndex): 61 (JSC::JSArray::arrayStorage): 62 (JSC::JSArray::setArrayStorage): 63 (JSC::JSArray::markChildrenDirect): 64 1 65 2010-07-29 Michael Saboff <msaboff@apple.com> 2 66 -
trunk/JavaScriptCore/jit/JITPropertyAccess.cpp
r64184 r64320 104 104 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr))); 105 105 106 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_ storage)), regT2);106 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT2); 107 107 addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); 108 108 109 loadPtr(BaseIndex(regT2, regT1, ScalePtr , OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0);109 loadPtr(BaseIndex(regT2, regT1, ScalePtr), regT0); 110 110 addSlowCase(branchTestPtr(Zero, regT0)); 111 111 … … 215 215 addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); 216 216 217 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2); 218 219 Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); 217 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT2); 218 Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr)); 220 219 221 220 Label storeResult(this); 222 221 emitGetVirtualRegister(value, regT0); 223 storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr , OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));222 storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr)); 224 223 Jump end = jump(); 225 224 226 225 empty.link(this); 227 add32(Imm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector) ));228 branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length) )).linkTo(storeResult, this);226 add32(Imm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)-OBJECT_OFFSETOF(ArrayStorage, m_vector))); 227 branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector))).linkTo(storeResult, this); 229 228 230 229 move(regT1, regT0); 231 230 add32(Imm32(1), regT0); 232 store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length) ));231 store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector))); 233 232 jump().linkTo(storeResult, this); 234 233 … … 727 726 728 727 // Checks out okay! - get the length from the storage 729 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2); 730 load32(Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2); 731 728 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT3); 729 load32(Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector)), regT2); 732 730 Jump failureCases2 = branch32(Above, regT2, Imm32(JSImmediate::maxImmediateInt)); 733 731 -
trunk/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
r64184 r64320 312 312 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr))); 313 313 314 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_ storage)), regT3);314 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT3); 315 315 addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); 316 316 317 load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF( ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag318 load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF( ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload317 load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag 318 load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload 319 319 addSlowCase(branch32(Equal, regT1, Imm32(JSValue::EmptyValueTag))); 320 320 … … 365 365 addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); 366 366 367 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_ storage)), regT3);368 369 Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF( ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::EmptyValueTag));367 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT3); 368 369 Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::EmptyValueTag)); 370 370 371 371 Label storeResult(this); 372 372 emitLoad(value, regT1, regT0); 373 store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF( ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); // payload374 store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF( ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); // tag373 store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); // payload 374 store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); // tag 375 375 Jump end = jump(); 376 376 377 377 empty.link(this); 378 add32(Imm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector) ));379 branch32(Below, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length) )).linkTo(storeResult, this);378 add32(Imm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)-OBJECT_OFFSETOF(ArrayStorage, m_vector))); 379 branch32(Below, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector))).linkTo(storeResult, this); 380 380 381 381 add32(Imm32(1), regT2, regT0); 382 store32(regT0, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length) ));382 store32(regT0, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector))); 383 383 jump().linkTo(storeResult, this); 384 384 … … 732 732 733 733 // Checks out okay! - get the length from the storage 734 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_ storage)), regT2);735 load32(Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length) ), regT2);734 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT2); 735 load32(Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector)), regT2); 736 736 737 737 Jump failureCases2 = branch32(Above, regT2, Imm32(INT_MAX)); -
trunk/JavaScriptCore/runtime/ArrayPrototype.cpp
r64184 r64320 425 425 } else { 426 426 result = thisObj->get(exec, 0); 427 for (unsigned k = 1; k < length; k++) { 428 if (JSValue obj = getProperty(exec, thisObj, k)) 429 thisObj->put(exec, k - 1, obj); 430 else 431 thisObj->deleteProperty(exec, k - 1); 432 } 433 thisObj->deleteProperty(exec, length - 1); 427 if (isJSArray(&exec->globalData(), thisObj)) 428 ((JSArray *)thisObj)->shiftCount(exec, 1); 429 else { 430 for (unsigned k = 1; k < length; k++) { 431 if (JSValue obj = getProperty(exec, thisObj, k)) 432 thisObj->put(exec, k - 1, obj); 433 else 434 thisObj->deleteProperty(exec, k - 1); 435 } 436 thisObj->deleteProperty(exec, length - 1); 437 } 434 438 putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - 1)); 435 439 } … … 579 583 if (additionalArgs != deleteCount) { 580 584 if (additionalArgs < deleteCount) { 581 for (unsigned k = begin; k < length - deleteCount; ++k) { 582 if (JSValue v = getProperty(exec, thisObj, k + deleteCount)) 583 thisObj->put(exec, k + additionalArgs, v); 584 else 585 thisObj->deleteProperty(exec, k + additionalArgs); 585 if ((!begin) && (isJSArray(&exec->globalData(), thisObj))) 586 ((JSArray *)thisObj)->shiftCount(exec, deleteCount - additionalArgs); 587 else { 588 for (unsigned k = begin; k < length - deleteCount; ++k) { 589 if (JSValue v = getProperty(exec, thisObj, k + deleteCount)) 590 thisObj->put(exec, k + additionalArgs, v); 591 else 592 thisObj->deleteProperty(exec, k + additionalArgs); 593 } 594 for (unsigned k = length; k > length - deleteCount + additionalArgs; --k) 595 thisObj->deleteProperty(exec, k - 1); 586 596 } 587 for (unsigned k = length; k > length - deleteCount + additionalArgs; --k)588 thisObj->deleteProperty(exec, k - 1);589 597 } else { 590 for (unsigned k = length - deleteCount; k > begin; --k) { 591 if (JSValue obj = getProperty(exec, thisObj, k + deleteCount - 1)) 592 thisObj->put(exec, k + additionalArgs - 1, obj); 593 else 594 thisObj->deleteProperty(exec, k + additionalArgs - 1); 598 if ((!begin) && (isJSArray(&exec->globalData(), thisObj))) 599 ((JSArray *)thisObj)->unshiftCount(exec, additionalArgs - deleteCount); 600 else { 601 for (unsigned k = length - deleteCount; k > begin; --k) { 602 if (JSValue obj = getProperty(exec, thisObj, k + deleteCount - 1)) 603 thisObj->put(exec, k + additionalArgs - 1, obj); 604 else 605 thisObj->deleteProperty(exec, k + additionalArgs - 1); 606 } 595 607 } 596 608 } … … 611 623 unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); 612 624 unsigned nrArgs = exec->argumentCount(); 613 if (nrArgs) { 614 for (unsigned k = length; k > 0; --k) { 615 if (JSValue v = getProperty(exec, thisObj, k - 1)) 616 thisObj->put(exec, k + nrArgs - 1, v); 617 else 618 thisObj->deleteProperty(exec, k + nrArgs - 1); 625 if ((nrArgs) && (length)) { 626 if (isJSArray(&exec->globalData(), thisObj)) 627 ((JSArray *)thisObj)->unshiftCount(exec, nrArgs); 628 else { 629 for (unsigned k = length; k > 0; --k) { 630 if (JSValue v = getProperty(exec, thisObj, k - 1)) 631 thisObj->put(exec, k + nrArgs - 1, v); 632 else 633 thisObj->deleteProperty(exec, k + nrArgs - 1); 634 } 619 635 } 620 636 } -
trunk/JavaScriptCore/runtime/JSArray.cpp
r64184 r64320 79 79 #define MAX_ARRAY_INDEX 0xFFFFFFFEU 80 80 81 // The value BASE_VECTOR_LEN is the maximum number of vector elements we'll allocate 82 // for an array that was created with a sepcified length (e.g. a = new Array(123)) 83 #define BASE_VECTOR_LEN 4U 84 85 // The upper bound to the size we'll grow a zero length array when the first element 86 // is added. 87 #define FIRST_VECTOR_GROW 4U 88 81 89 // Our policy for when to use a vector and when to use a sparse map. 82 90 // For all array indices under MIN_SPARSE_ARRAY_INDEX, we always use a vector. … … 86 94 87 95 const ClassInfo JSArray::info = {"Array", 0, 0, 0}; 96 97 // We keep track of the size of the last array after it was grown. We use this 98 // as a simple heuristic for as the value to grow the next array from size 0. 99 // This value is capped by the constant FIRST_VECTOR_GROW defined above. 100 static unsigned lastArraySize = 0; 88 101 89 102 static inline size_t storageSize(unsigned vectorLength) … … 101 114 } 102 115 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 116 static inline bool isDenseEnoughForVector(unsigned length, unsigned numValues) 119 117 { … … 134 132 unsigned initialCapacity = 0; 135 133 136 m_storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity))); 134 ArrayStorage* storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity))); 135 m_indexBias = 0; 136 setArrayStorage(storage); 137 137 m_vectorLength = initialCapacity; 138 138 … … 147 147 initialCapacity = initialLength; 148 148 else 149 initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX); 150 151 m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity))); 149 initialCapacity = min(BASE_VECTOR_LEN, MIN_SPARSE_ARRAY_INDEX); 150 151 ArrayStorage* storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity))); 152 storage->m_length = initialLength; 153 m_indexBias = 0; 152 154 m_vectorLength = initialCapacity; 153 m_storage->m_sparseValueMap = 0; 154 m_storage->subclassData = 0; 155 m_storage->reportedMapCapacity = 0; 155 setArrayStorage(storage); 156 storage->m_sparseValueMap = 0; 157 storage->subclassData = 0; 158 storage->reportedMapCapacity = 0; 156 159 157 160 if (creationMode == CreateCompact) { 158 161 #if CHECK_ARRAY_CONSISTENCY 159 m_storage->m_inCompactInitialization = !!initialCapacity;162 storage->m_inCompactInitialization = !!initialCapacity; 160 163 #endif 161 m_storage->m_length = 0;162 m_storage->m_numValuesInVector = initialCapacity;164 storage->m_length = 0; 165 storage->m_numValuesInVector = initialCapacity; 163 166 } else { 164 167 #if CHECK_ARRAY_CONSISTENCY 165 m_storage->m_inCompactInitialization = false;168 storage->m_inCompactInitialization = false; 166 169 #endif 167 m_storage->m_length = initialLength;168 m_storage->m_numValuesInVector = 0;169 JSValue* vector = m_ storage->m_vector;170 storage->m_length = initialLength; 171 storage->m_numValuesInVector = 0; 172 JSValue* vector = m_vector; 170 173 for (size_t i = 0; i < initialCapacity; ++i) 171 174 vector[i] = JSValue(); … … 173 176 174 177 checkConsistency(); 175 178 176 179 Heap::heap(this)->reportExtraMemoryCost(initialCapacity * sizeof(JSValue)); 177 180 } … … 182 185 unsigned initialCapacity = list.size(); 183 186 184 m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity))); 185 m_storage->m_length = initialCapacity; 187 ArrayStorage* storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity))); 188 m_indexBias = 0; 189 storage->m_length = initialCapacity; 186 190 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 storage->m_numValuesInVector = initialCapacity; 192 storage->m_sparseValueMap = 0; 193 storage->subclassData = 0; 194 storage->reportedMapCapacity = 0; 191 195 #if CHECK_ARRAY_CONSISTENCY 192 m_storage->m_inCompactInitialization = false;196 storage->m_inCompactInitialization = false; 193 197 #endif 198 setArrayStorage(storage); 194 199 195 200 size_t i = 0; 201 JSValue* vector = m_vector; 196 202 ArgList::const_iterator end = list.end(); 197 203 for (ArgList::const_iterator it = list.begin(); it != end; ++it, ++i) 198 m_storage->m_vector[i] = *it;204 vector[i] = *it; 199 205 200 206 checkConsistency(); … … 208 214 checkConsistency(DestructorConsistencyCheck); 209 215 210 delete m_storage->m_sparseValueMap; 211 fastFree(m_storage); 216 ArrayStorage* storage = arrayStorage(); 217 delete storage->m_sparseValueMap; 218 char* realStorage = reinterpret_cast<char*>(storage) - (m_indexBias * sizeof(JSValue)); 219 fastFree(realStorage); 212 220 } 213 221 214 222 bool JSArray::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot) 215 223 { 216 ArrayStorage* storage = m_storage;217 224 ArrayStorage* storage = arrayStorage(); 225 218 226 if (i >= storage->m_length) { 219 227 if (i > MAX_ARRAY_INDEX) … … 223 231 224 232 if (i < m_vectorLength) { 225 JSValue& valueSlot = storage->m_vector[i];233 JSValue& valueSlot = m_vector[i]; 226 234 if (valueSlot) { 227 235 slot.setValueSlot(&valueSlot); … … 262 270 return true; 263 271 } 272 273 ArrayStorage* storage = arrayStorage(); 264 274 265 275 bool isArrayIndex; 266 276 unsigned i = propertyName.toArrayIndex(&isArrayIndex); 267 277 if (isArrayIndex) { 268 if (i >= m_storage->m_length)278 if (i >= storage->m_length) 269 279 return false; 270 280 if (i < m_vectorLength) { 271 JSValue& value = m_ storage->m_vector[i];281 JSValue& value = m_vector[i]; 272 282 if (value) { 273 283 descriptor.setDescriptor(value, 0); 274 284 return true; 275 285 } 276 } else if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {286 } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) { 277 287 if (i >= MIN_SPARSE_ARRAY_INDEX) { 278 288 SparseArrayValueMap::iterator it = map->find(i); … … 314 324 checkConsistency(); 315 325 316 unsigned length = m_storage->m_length; 326 ArrayStorage* storage = arrayStorage(); 327 328 unsigned length = storage->m_length; 317 329 if (i >= length && i <= MAX_ARRAY_INDEX) { 318 330 length = i + 1; 319 m_storage->m_length = length;331 storage->m_length = length; 320 332 } 321 333 322 334 if (i < m_vectorLength) { 323 JSValue& valueSlot = m_ storage->m_vector[i];335 JSValue& valueSlot = m_vector[i]; 324 336 if (valueSlot) { 325 337 valueSlot = value; … … 328 340 } 329 341 valueSlot = value; 330 ++ m_storage->m_numValuesInVector;342 ++storage->m_numValuesInVector; 331 343 checkConsistency(); 332 344 return; … … 338 350 NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue value) 339 351 { 340 ArrayStorage* storage = m_storage; 352 ArrayStorage* storage = arrayStorage(); 353 341 354 SparseArrayValueMap* map = storage->m_sparseValueMap; 342 355 … … 375 388 if (!map || map->isEmpty()) { 376 389 if (increaseVectorLength(i + 1)) { 377 storage = m_storage; 378 storage->m_vector[i] = value; 379 ++storage->m_numValuesInVector; 390 m_vector[i] = value; 391 ++arrayStorage()->m_numValuesInVector; 380 392 checkConsistency(); 381 393 } else … … 386 398 // Decide how many values it would be best to move from the map. 387 399 unsigned newNumValuesInVector = storage->m_numValuesInVector + 1; 388 unsigned newVectorLength = increasedVectorLength(i + 1);400 unsigned newVectorLength = getNewVectorLength(i + 1); 389 401 for (unsigned j = max(m_vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) 390 402 newNumValuesInVector += map->contains(j); … … 395 407 // If newVectorLength is already the maximum - MAX_STORAGE_VECTOR_LENGTH - then do not attempt to grow any further. 396 408 while (newVectorLength < MAX_STORAGE_VECTOR_LENGTH) { 397 unsigned proposedNewVectorLength = increasedVectorLength(newVectorLength + 1);409 unsigned proposedNewVectorLength = getNewVectorLength(newVectorLength + 1); 398 410 for (unsigned j = max(newVectorLength, MIN_SPARSE_ARRAY_INDEX); j < proposedNewVectorLength; ++j) 399 411 proposedNewNumValuesInVector += map->contains(j); … … 405 417 } 406 418 407 if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage)) { 419 int baseBias = m_indexBias * sizeof(JSValue); 420 char* baseStorage = reinterpret_cast<char*>(storage - baseBias); 421 422 if (!tryFastRealloc(baseStorage, storageSize(newVectorLength + m_indexBias)).getValue(baseStorage)) { 408 423 throwOutOfMemoryError(exec); 409 424 return; 410 425 } 411 426 427 storage = reinterpret_cast<ArrayStorage*>(baseStorage + baseBias); 428 setArrayStorage(storage); 429 412 430 unsigned vectorLength = m_vectorLength; 413 431 414 432 if (newNumValuesInVector == storage->m_numValuesInVector + 1) { 415 433 for (unsigned j = vectorLength; j < newVectorLength; ++j) 416 storage->m_vector[j] = JSValue();434 m_vector[j] = JSValue(); 417 435 if (i > MIN_SPARSE_ARRAY_INDEX) 418 436 map->remove(i); 419 437 } else { 420 438 for (unsigned j = vectorLength; j < max(vectorLength, MIN_SPARSE_ARRAY_INDEX); ++j) 421 storage->m_vector[j] = JSValue();439 m_vector[j] = JSValue(); 422 440 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;441 m_vector[j] = map->take(j); 442 } 443 444 ASSERT(i < newVectorLength); 427 445 428 446 m_vectorLength = newVectorLength; 429 447 storage->m_numValuesInVector = newNumValuesInVector; 430 448 431 m_ storage = storage;449 m_vector[i] = value; 432 450 433 451 checkConsistency(); … … 453 471 checkConsistency(); 454 472 455 ArrayStorage* storage = m_storage;456 473 ArrayStorage* storage = arrayStorage(); 474 457 475 if (i < m_vectorLength) { 458 JSValue& valueSlot = storage->m_vector[i];476 JSValue& valueSlot = m_vector[i]; 459 477 if (!valueSlot) { 460 478 checkConsistency(); … … 492 510 // which almost certainly means a different structure for PropertyNameArray. 493 511 494 ArrayStorage* storage = m_storage;495 512 ArrayStorage* storage = arrayStorage(); 513 496 514 unsigned usedVectorLength = min(storage->m_length, m_vectorLength); 497 515 for (unsigned i = 0; i < usedVectorLength; ++i) { 498 if ( storage->m_vector[i])516 if (m_vector[i]) 499 517 propertyNames.add(Identifier::from(exec, i)); 500 518 } … … 512 530 } 513 531 532 ALWAYS_INLINE unsigned JSArray::getNewVectorLength(unsigned desiredLength) 533 { 534 ASSERT(desiredLength <= MAX_STORAGE_VECTOR_LENGTH); 535 536 unsigned increasedLength; 537 unsigned length = arrayStorage()->m_length; 538 539 if (desiredLength < length) 540 increasedLength = length; 541 else if (!m_vectorLength) 542 increasedLength = max(desiredLength, lastArraySize); 543 else { 544 // Mathematically equivalent to: 545 // increasedLength = (newLength * 3 + 1) / 2; 546 // or: 547 // increasedLength = (unsigned)ceil(newLength * 1.5)); 548 // This form is not prone to internal overflow. 549 increasedLength = desiredLength + (desiredLength >> 1) + (desiredLength & 1); 550 } 551 552 ASSERT(increasedLength >= desiredLength); 553 554 lastArraySize = min(increasedLength, FIRST_VECTOR_GROW); 555 556 return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH); 557 } 558 514 559 bool JSArray::increaseVectorLength(unsigned newLength) 515 560 { … … 517 562 // to the vector. Callers have to account for that, because they can do it more efficiently. 518 563 519 ArrayStorage* storage = m_storage;564 ArrayStorage* storage = arrayStorage(); 520 565 521 566 unsigned vectorLength = m_vectorLength; 522 567 ASSERT(newLength > vectorLength); 523 568 ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX); 524 unsigned newVectorLength = increasedVectorLength(newLength); 525 526 if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage)) 569 unsigned newVectorLength = getNewVectorLength(newLength); 570 int baseBias = m_indexBias * sizeof(JSValue); 571 char* baseStorage = reinterpret_cast<char*>(storage) - baseBias; 572 573 if (!tryFastRealloc(baseStorage, storageSize(newVectorLength + m_indexBias)).getValue(baseStorage)) 527 574 return false; 575 576 storage = reinterpret_cast<ArrayStorage*>(baseStorage + baseBias); 577 setArrayStorage(storage); 578 579 JSValue* vector = m_vector; 580 for (unsigned i = vectorLength; i < newVectorLength; ++i) 581 vector[i] = JSValue(); 528 582 529 583 m_vectorLength = newVectorLength; 530 531 for (unsigned i = vectorLength; i < newVectorLength; ++i) 532 storage->m_vector[i] = JSValue(); 533 534 m_storage = storage; 535 584 536 585 Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); 537 586 538 587 return true; 539 588 } 589 590 bool JSArray::increaseVectorPrefixLength(unsigned newLength) 591 { 592 // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map 593 // to the vector. Callers have to account for that, because they can do it more efficiently. 594 595 ArrayStorage* storage = arrayStorage(); 596 ArrayStorage* newStorage; 597 598 unsigned vectorLength = m_vectorLength; 599 ASSERT(newLength > vectorLength); 600 ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX); 601 unsigned newVectorLength = getNewVectorLength(newLength); 602 char* baseStorage = reinterpret_cast<char*>(storage) - (m_indexBias * sizeof(JSValue)); 603 604 char* newBaseStorage = reinterpret_cast<char*>(fastMalloc(storageSize(newVectorLength + m_indexBias))); 605 if (!newBaseStorage) 606 return false; 607 608 m_indexBias += newVectorLength - newLength; 609 int newStorageOffset = m_indexBias * sizeof(JSValue); 610 611 newStorage = reinterpret_cast<ArrayStorage*>(newBaseStorage + newStorageOffset); 612 613 memcpy(newStorage, storage, storageSize(0)); 614 memcpy(&newStorage->m_vector[newLength - m_vectorLength], &storage->m_vector[0], storage->m_length * sizeof(JSValue)); 615 616 m_vectorLength = newLength; 617 618 fastFree(baseStorage); 619 620 setArrayStorage(newStorage); 621 622 Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); 623 624 return true; 625 } 626 540 627 541 628 void JSArray::setLength(unsigned newLength) … … 548 635 #endif 549 636 550 ArrayStorage* storage = m_storage;551 552 unsigned length = m_storage->m_length;637 ArrayStorage* storage = arrayStorage(); 638 639 unsigned length = storage->m_length; 553 640 554 641 if (newLength < length) { 555 642 unsigned usedVectorLength = min(length, m_vectorLength); 556 643 for (unsigned i = newLength; i < usedVectorLength; ++i) { 557 JSValue& valueSlot = storage->m_vector[i];644 JSValue& valueSlot = m_vector[i]; 558 645 bool hadValue = valueSlot; 559 646 valueSlot = JSValue(); … … 575 662 } 576 663 577 m_storage->m_length = newLength;664 storage->m_length = newLength; 578 665 579 666 checkConsistency(); … … 584 671 checkConsistency(); 585 672 586 unsigned length = m_storage->m_length; 673 ArrayStorage* storage = arrayStorage(); 674 675 unsigned length = storage->m_length; 587 676 if (!length) 588 677 return jsUndefined(); … … 593 682 594 683 if (length < m_vectorLength) { 595 JSValue& valueSlot = m_ storage->m_vector[length];684 JSValue& valueSlot = m_vector[length]; 596 685 if (valueSlot) { 597 -- m_storage->m_numValuesInVector;686 --storage->m_numValuesInVector; 598 687 result = valueSlot; 599 688 valueSlot = JSValue(); … … 602 691 } else { 603 692 result = jsUndefined(); 604 if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {693 if (SparseArrayValueMap* map = storage->m_sparseValueMap) { 605 694 SparseArrayValueMap::iterator it = map->find(length); 606 695 if (it != map->end()) { … … 609 698 if (map->isEmpty()) { 610 699 delete map; 611 m_storage->m_sparseValueMap = 0;700 storage->m_sparseValueMap = 0; 612 701 } 613 702 } … … 615 704 } 616 705 617 m_storage->m_length = length;706 storage->m_length = length; 618 707 619 708 checkConsistency(); … … 625 714 { 626 715 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; 716 717 ArrayStorage* storage = arrayStorage(); 718 719 if (storage->m_length < m_vectorLength) { 720 m_vector[storage->m_length] = value; 721 ++storage->m_numValuesInVector; 722 ++storage->m_length; 632 723 checkConsistency(); 633 724 return; 634 725 } 635 726 636 if ( m_storage->m_length < MIN_SPARSE_ARRAY_INDEX) {637 SparseArrayValueMap* map = m_storage->m_sparseValueMap;727 if (storage->m_length < MIN_SPARSE_ARRAY_INDEX) { 728 SparseArrayValueMap* map = storage->m_sparseValueMap; 638 729 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; 730 if (increaseVectorLength(storage->m_length + 1)) { 731 storage = arrayStorage(); 732 m_vector[storage->m_length] = value; 733 ++storage->m_numValuesInVector; 734 ++storage->m_length; 643 735 checkConsistency(); 644 736 return; … … 650 742 } 651 743 652 putSlowCase(exec, m_storage->m_length++, value); 744 putSlowCase(exec, storage->m_length++, value); 745 } 746 747 void JSArray::shiftCount(ExecState* exec, int count) 748 { 749 ASSERT(count > 0); 750 751 ArrayStorage* storage = arrayStorage(); 752 753 unsigned oldLength = storage->m_length; 754 755 if (!oldLength) 756 return; 757 758 if (oldLength != storage->m_numValuesInVector) { 759 // If m_length and m_numValuesInVector aren't the same, we have a sparse vector 760 // which means we need to go through each entry looking for the the "empty" 761 // slots and then fill them with possible properties. See ECMA spec. 762 // 15.4.4.9 steps 11 through 13. 763 for (unsigned i = count; i < oldLength; ++i) { 764 if ((i >= m_vectorLength) || (!m_vector[i])) { 765 PropertySlot slot(this); 766 JSValue p = prototype(); 767 if ((!p.isNull()) && (asObject(p)->getPropertySlot(exec, i, slot))) 768 put(exec, i, slot.getValue(exec, i)); 769 } 770 } 771 772 storage = arrayStorage(); // The put() above could have grown the vector and realloc'ed storage. 773 774 // Need to decrement numValuesInvector based on number of real entries 775 for (unsigned i = 0; i < (unsigned)count; ++i) 776 if ((i < m_vectorLength) && (m_vector[i])) 777 --storage->m_numValuesInVector; 778 } else 779 storage->m_numValuesInVector -= count; 780 781 storage->m_length -= count; 782 783 if (m_vectorLength) { 784 count = min(m_vectorLength, (unsigned)count); 785 786 m_vectorLength -= count; 787 788 if (m_vectorLength) { 789 char* newBaseStorage = reinterpret_cast<char*>(storage) + count * sizeof(JSValue); 790 memmove(newBaseStorage, storage, storageSize(0)); 791 storage = reinterpret_cast<ArrayStorage*>(newBaseStorage); 792 793 m_indexBias += count; 794 setArrayStorage(storage); 795 } 796 } 797 } 798 799 void JSArray::unshiftCount(ExecState* exec, int count) 800 { 801 ArrayStorage* storage = arrayStorage(); 802 803 ASSERT(m_indexBias >= 0); 804 ASSERT(count >= 0); 805 806 unsigned length = storage->m_length; 807 808 if (length != storage->m_numValuesInVector) { 809 // If m_length and m_numValuesInVector aren't the same, we have a sparse vector 810 // which means we need to go through each entry looking for the the "empty" 811 // slots and then fill them with possible properties. See ECMA spec. 812 // 15.4.4.13 steps 8 through 10. 813 for (unsigned i = 0; i < length; ++i) { 814 if ((i >= m_vectorLength) || (!m_vector[i])) { 815 PropertySlot slot(this); 816 JSValue p = prototype(); 817 if ((!p.isNull()) && (asObject(p)->getPropertySlot(exec, i, slot))) 818 put(exec, i, slot.getValue(exec, i)); 819 } 820 } 821 } 822 823 storage = arrayStorage(); // The put() above could have grown the vector and realloc'ed storage. 824 825 if (m_indexBias >= count) { 826 m_indexBias -= count; 827 char* newBaseStorage = reinterpret_cast<char*>(storage) - count * sizeof(JSValue); 828 memmove(newBaseStorage, storage, storageSize(0)); 829 storage = reinterpret_cast<ArrayStorage*>(newBaseStorage); 830 setArrayStorage(storage); 831 m_vectorLength += count; 832 } else if ((!m_indexBias) && (!increaseVectorPrefixLength(m_vectorLength + count))) { 833 throwOutOfMemoryError(exec); 834 return; 835 } 653 836 } 654 837 … … 676 859 void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) 677 860 { 861 ArrayStorage* storage = arrayStorage(); 862 678 863 unsigned lengthNotIncludingUndefined = compactForSorting(); 679 if ( m_storage->m_sparseValueMap) {864 if (storage->m_sparseValueMap) { 680 865 throwOutOfMemoryError(exec); 681 866 return; … … 686 871 687 872 bool allValuesAreNumbers = true; 688 size_t size = m_storage->m_numValuesInVector;873 size_t size = storage->m_numValuesInVector; 689 874 for (size_t i = 0; i < size; ++i) { 690 if (!m_ storage->m_vector[i].isNumber()) {875 if (!m_vector[i].isNumber()) { 691 876 allValuesAreNumbers = false; 692 877 break; … … 700 885 // also don't require mergesort's stability, since there's no user visible 701 886 // side-effect from swapping the order of equal primitive values. 702 qsort(m_ storage->m_vector, size, sizeof(JSValue), compareNumbersForQSort);887 qsort(m_vector, size, sizeof(JSValue), compareNumbersForQSort); 703 888 704 889 checkConsistency(SortConsistencyCheck); … … 707 892 void JSArray::sort(ExecState* exec) 708 893 { 894 ArrayStorage* storage = arrayStorage(); 895 709 896 unsigned lengthNotIncludingUndefined = compactForSorting(); 710 if ( m_storage->m_sparseValueMap) {897 if (storage->m_sparseValueMap) { 711 898 throwOutOfMemoryError(exec); 712 899 return; … … 728 915 729 916 for (size_t i = 0; i < lengthNotIncludingUndefined; i++) { 730 JSValue value = m_ storage->m_vector[i];917 JSValue value = m_vector[i]; 731 918 ASSERT(!value.isUndefined()); 732 919 values[i].first = value; … … 760 947 761 948 for (size_t i = 0; i < lengthNotIncludingUndefined; i++) 762 m_ storage->m_vector[i] = values[i].first;949 m_vector[i] = values[i].first; 763 950 764 951 checkConsistency(SortConsistencyCheck); … … 847 1034 checkConsistency(); 848 1035 1036 ArrayStorage* storage = arrayStorage(); 1037 849 1038 // FIXME: This ignores exceptions raised in the compare function or in toNumber. 850 1039 851 1040 // The maximum tree depth is compiled in - but the caller is clearly up to no good 852 1041 // 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);1042 ASSERT(storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max())); 1043 if (storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max())) 1044 return; 1045 1046 if (!storage->m_length) 1047 return; 1048 1049 unsigned usedVectorLength = min(storage->m_length, m_vectorLength); 861 1050 862 1051 AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items … … 866 1055 tree.abstractor().m_compareCallData = &callData; 867 1056 tree.abstractor().m_globalThisValue = exec->globalThisValue(); 868 tree.abstractor().m_nodes.resize(usedVectorLength + ( m_storage->m_sparseValueMap ? m_storage->m_sparseValueMap->size() : 0));1057 tree.abstractor().m_nodes.resize(usedVectorLength + (storage->m_sparseValueMap ? storage->m_sparseValueMap->size() : 0)); 869 1058 870 1059 if (callType == CallTypeJS) … … 884 1073 // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree. 885 1074 for (; numDefined < usedVectorLength; ++numDefined) { 886 JSValue v = m_ storage->m_vector[numDefined];1075 JSValue v = m_vector[numDefined]; 887 1076 if (!v || v.isUndefined()) 888 1077 break; … … 891 1080 } 892 1081 for (unsigned i = numDefined; i < usedVectorLength; ++i) { 893 JSValue v = m_ storage->m_vector[i];1082 JSValue v = m_vector[i]; 894 1083 if (v) { 895 1084 if (v.isUndefined()) … … 905 1094 unsigned newUsedVectorLength = numDefined + numUndefined; 906 1095 907 if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {1096 if (SparseArrayValueMap* map = storage->m_sparseValueMap) { 908 1097 newUsedVectorLength += map->size(); 909 1098 if (newUsedVectorLength > m_vectorLength) { … … 914 1103 } 915 1104 } 1105 1106 storage = arrayStorage(); 916 1107 917 1108 SparseArrayValueMap::iterator end = map->end(); … … 923 1114 924 1115 delete map; 925 m_storage->m_sparseValueMap = 0;1116 storage->m_sparseValueMap = 0; 926 1117 } 927 1118 … … 935 1126 iter.start_iter_least(tree); 936 1127 for (unsigned i = 0; i < numDefined; ++i) { 937 m_ storage->m_vector[i] = tree.abstractor().m_nodes[*iter].value;1128 m_vector[i] = tree.abstractor().m_nodes[*iter].value; 938 1129 ++iter; 939 1130 } … … 941 1132 // Put undefined values back in. 942 1133 for (unsigned i = numDefined; i < newUsedVectorLength; ++i) 943 m_ storage->m_vector[i] = jsUndefined();1134 m_vector[i] = jsUndefined(); 944 1135 945 1136 // Ensure that unused values in the vector are zeroed out. 946 1137 for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) 947 m_ storage->m_vector[i] = JSValue();948 949 m_storage->m_numValuesInVector = newUsedVectorLength;1138 m_vector[i] = JSValue(); 1139 1140 storage->m_numValuesInVector = newUsedVectorLength; 950 1141 951 1142 checkConsistency(SortConsistencyCheck); … … 954 1145 void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) 955 1146 { 956 JSValue* vector = m_storage->m_vector; 957 unsigned vectorEnd = min(m_storage->m_length, m_vectorLength); 1147 ArrayStorage* storage = arrayStorage(); 1148 1149 JSValue* vector = storage->m_vector; 1150 unsigned vectorEnd = min(storage->m_length, m_vectorLength); 958 1151 unsigned i = 0; 959 1152 for (; i < vectorEnd; ++i) { … … 964 1157 } 965 1158 966 for (; i < m_storage->m_length; ++i)1159 for (; i < storage->m_length; ++i) 967 1160 args.append(get(exec, i)); 968 1161 } … … 970 1163 void JSArray::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize) 971 1164 { 972 ASSERT( m_storage->m_length >= maxSize);1165 ASSERT(arrayStorage()->m_length >= maxSize); 973 1166 UNUSED_PARAM(maxSize); 974 JSValue* vector = m_ storage->m_vector;1167 JSValue* vector = m_vector; 975 1168 unsigned vectorEnd = min(maxSize, m_vectorLength); 976 1169 unsigned i = 0; … … 990 1183 checkConsistency(); 991 1184 992 ArrayStorage* storage = m_storage;993 994 unsigned usedVectorLength = min( m_storage->m_length, m_vectorLength);1185 ArrayStorage* storage = arrayStorage(); 1186 1187 unsigned usedVectorLength = min(storage->m_length, m_vectorLength); 995 1188 996 1189 unsigned numDefined = 0; … … 998 1191 999 1192 for (; numDefined < usedVectorLength; ++numDefined) { 1000 JSValue v = storage->m_vector[numDefined];1193 JSValue v = m_vector[numDefined]; 1001 1194 if (!v || v.isUndefined()) 1002 1195 break; 1003 1196 } 1004 1197 for (unsigned i = numDefined; i < usedVectorLength; ++i) { 1005 JSValue v = storage->m_vector[i];1198 JSValue v = m_vector[i]; 1006 1199 if (v) { 1007 1200 if (v.isUndefined()) 1008 1201 ++numUndefined; 1009 1202 else 1010 storage->m_vector[numDefined++] = v;1203 m_vector[numDefined++] = v; 1011 1204 } 1012 1205 } … … 1021 1214 if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) 1022 1215 return 0; 1023 storage = m_storage; 1216 1217 storage = arrayStorage(); 1024 1218 } 1025 1219 1026 1220 SparseArrayValueMap::iterator end = map->end(); 1027 1221 for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) 1028 storage->m_vector[numDefined++] = it->second;1222 m_vector[numDefined++] = it->second; 1029 1223 1030 1224 delete map; … … 1033 1227 1034 1228 for (unsigned i = numDefined; i < newUsedVectorLength; ++i) 1035 storage->m_vector[i] = jsUndefined();1229 m_vector[i] = jsUndefined(); 1036 1230 for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) 1037 storage->m_vector[i] = JSValue();1231 m_vector[i] = JSValue(); 1038 1232 1039 1233 storage->m_numValuesInVector = newUsedVectorLength; … … 1046 1240 void* JSArray::subclassData() const 1047 1241 { 1048 return m_storage->subclassData;1242 return arrayStorage()->subclassData; 1049 1243 } 1050 1244 1051 1245 void JSArray::setSubclassData(void* d) 1052 1246 { 1053 m_storage->subclassData = d;1247 arrayStorage()->subclassData = d; 1054 1248 } 1055 1249 … … 1058 1252 void JSArray::checkConsistency(ConsistencyCheckType type) 1059 1253 { 1060 ASSERT(m_storage); 1254 ArrayStorage* storage = arrayStorage(); 1255 1256 ASSERT(storage); 1061 1257 if (type == SortConsistencyCheck) 1062 ASSERT(! m_storage->m_sparseValueMap);1258 ASSERT(!storage->m_sparseValueMap); 1063 1259 1064 1260 unsigned numValuesInVector = 0; 1065 1261 for (unsigned i = 0; i < m_vectorLength; ++i) { 1066 if (JSValue value = m_ storage->m_vector[i]) {1067 ASSERT(i < m_storage->m_length);1262 if (JSValue value = m_vector[i]) { 1263 ASSERT(i < storage->m_length); 1068 1264 if (type != DestructorConsistencyCheck) 1069 1265 value.isUndefined(); // Likely to crash if the object was deallocated. … … 1071 1267 } else { 1072 1268 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) {1269 ASSERT(i >= storage->m_numValuesInVector); 1270 } 1271 } 1272 ASSERT(numValuesInVector == storage->m_numValuesInVector); 1273 ASSERT(numValuesInVector <= storage->m_length); 1274 1275 if (storage->m_sparseValueMap) { 1276 SparseArrayValueMap::iterator end = storage->m_sparseValueMap->end(); 1277 for (SparseArrayValueMap::iterator it = storage->m_sparseValueMap->begin(); it != end; ++it) { 1082 1278 unsigned index = it->first; 1083 ASSERT(index < m_storage->m_length);1279 ASSERT(index < storage->m_length); 1084 1280 ASSERT(index >= m_vectorLength); 1085 1281 ASSERT(index <= MAX_ARRAY_INDEX); -
trunk/JavaScriptCore/runtime/JSArray.h
r64184 r64320 30 30 typedef HashMap<unsigned, JSValue> SparseArrayValueMap; 31 31 32 // This struct holds the actual data values of an array. A JSArray object points to it's contained ArrayStorage 33 // struct by pointing to m_vector. To access the contained ArrayStorage struct, use the getStorage() and 34 // setStorage() methods. It is important to note that there may be space before the ArrayStorage that 35 // is used to quick unshift / shift operation. The actual allocated pointer is available by using: 36 // getStorage() - m_indexBias * sizeof(JSValue) 32 37 struct ArrayStorage { 33 unsigned m_length; 38 unsigned m_length; // The "length" property on the array 34 39 unsigned m_numValuesInVector; 35 40 SparseArrayValueMap* m_sparseValueMap; … … 68 73 69 74 static JS_EXPORTDATA const ClassInfo info; 70 71 unsigned length() const { return m_storage->m_length; }75 76 unsigned length() const { return arrayStorage()->m_length; } 72 77 void setLength(unsigned); // OK to use on new arrays, but not if it might be a RegExpMatchArray. 73 78 … … 79 84 JSValue pop(); 80 85 81 bool canGetIndex(unsigned i) { return i < m_vectorLength && m_storage->m_vector[i]; } 86 void shiftCount(ExecState*, int count); 87 void unshiftCount(ExecState*, int count); 88 89 bool canGetIndex(unsigned i) { return i < m_vectorLength && m_vector[i]; } 82 90 JSValue getIndex(unsigned i) 83 91 { 84 92 ASSERT(canGetIndex(i)); 85 return m_ storage->m_vector[i];93 return m_vector[i]; 86 94 } 87 95 … … 90 98 { 91 99 ASSERT(canSetIndex(i)); 92 JSValue& x = m_storage->m_vector[i]; 100 101 JSValue& x = m_vector[i]; 93 102 if (!x) { 94 ++m_storage->m_numValuesInVector; 95 if (i >= m_storage->m_length) 96 m_storage->m_length = i + 1; 103 ArrayStorage *storage = arrayStorage(); 104 ++storage->m_numValuesInVector; 105 if (i >= storage->m_length) 106 storage->m_length = i + 1; 97 107 } 98 108 x = v; 99 109 } 100 110 101 111 void uncheckedSetIndex(unsigned i, JSValue v) 102 112 { 103 113 ASSERT(canSetIndex(i)); 114 ArrayStorage *storage = arrayStorage(); 104 115 #if CHECK_ARRAY_CONSISTENCY 105 ASSERT( m_storage->m_inCompactInitialization);116 ASSERT(storage->m_inCompactInitialization); 106 117 #endif 107 m_storage->m_vector[i] = v;118 storage->m_vector[i] = v; 108 119 } 109 120 … … 128 139 void* subclassData() const; 129 140 void setSubclassData(void*); 141 142 inline ArrayStorage *arrayStorage() const 143 { 144 return reinterpret_cast<ArrayStorage*>(reinterpret_cast<char*>(m_vector) - (sizeof(ArrayStorage) - sizeof(JSValue))); 145 } 146 147 inline void setArrayStorage(ArrayStorage *storage) 148 { 149 m_vector = &storage->m_vector[0]; 150 } 130 151 131 152 private: … … 135 156 void putSlowCase(ExecState*, unsigned propertyName, JSValue); 136 157 158 unsigned getNewVectorLength(unsigned desiredLength); 137 159 bool increaseVectorLength(unsigned newLength); 160 bool increaseVectorPrefixLength(unsigned newLength); 138 161 139 162 unsigned compactForSorting(); … … 142 165 void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck); 143 166 144 unsigned m_vectorLength; 145 ArrayStorage* m_storage; 167 unsigned m_vectorLength; // The valid length of m_vector 168 int m_indexBias; // The number of JSValue sized blocks before ArrayStorage. 169 JSValue* m_vector; // Copy of ArrayStorage.m_vector. Used for quick vector access and to materialize ArrayStorage ptr. 146 170 }; 147 171 … … 169 193 JSObject::markChildrenDirect(markStack); 170 194 171 ArrayStorage* storage = m_storage;195 ArrayStorage* storage = arrayStorage(); 172 196 173 197 unsigned usedVectorLength = std::min(storage->m_length, m_vectorLength);
Note: See TracChangeset
for help on using the changeset viewer.