Changeset 34496 in webkit for trunk/JavaScriptCore
- Timestamp:
- Jun 11, 2008, 12:37:44 PM (17 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r34487 r34496 1 2008-06-11 Darin Adler <[email protected]> 2 3 Reviewed by Alexey. 4 5 - fix https://bugs.webkit.org/show_bug.cgi?id=19442 6 JavaScript array implementation doesn't maintain m_numValuesInVector when sorting 7 8 * kjs/array_instance.cpp: 9 (KJS::ArrayInstance::checkConsistency): Added. Empty inline version for when 10 consistency checks are turned off. 11 (KJS::ArrayInstance::ArrayInstance): Check consistency after construction. 12 (KJS::ArrayInstance::~ArrayInstance): Check consistency before destruction. 13 (KJS::ArrayInstance::put): Check consistency before and after. 14 (KJS::ArrayInstance::deleteProperty): Ditto. 15 (KJS::ArrayInstance::setLength): Ditto. 16 (KJS::compareByStringPairForQSort): Use typedef for clarity. 17 (KJS::ArrayInstance::sort): Check consistency before and after. Also broke the loop 18 to set up sorting into two separate passes. Added FIXMEs about various exception 19 safety issues. Added code to set m_numValuesInVector after sorting. 20 (KJS::ArrayInstance::compactForSorting): Ditto. 21 22 * kjs/array_instance.h: Added a definition of an enum for the types of consistency 23 check and a declaration of the consistency checking function. 24 1 25 2008-06-10 Kevin Ollivier <[email protected]> 2 26 -
trunk/JavaScriptCore/kjs/array_instance.cpp
r34355 r34496 28 28 #include <wtf/AVLTree.h> 29 29 30 #define CHECK_ARRAY_CONSISTENCY 0 31 30 32 using namespace std; 31 33 … … 41 43 }; 42 44 43 // 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer 45 // 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer. 44 46 static const unsigned maxArrayIndex = 0xFFFFFFFEU; 45 47 … … 70 72 } 71 73 74 #if !CHECK_ARRAY_CONSISTENCY 75 76 inline void ArrayInstance::checkConsistency(ConsistencyCheckType) 77 { 78 } 79 80 #endif 81 72 82 ArrayInstance::ArrayInstance(JSObject* prototype, unsigned initialLength) 73 83 : JSObject(prototype) … … 80 90 81 91 Collector::reportExtraMemoryCost(initialCapacity * sizeof(JSValue*)); 92 93 checkConsistency(); 82 94 } 83 95 … … 104 116 // When the array is created non-empty, its cells are filled, so it's really no worse than 105 117 // a property map. Therefore don't report extra memory cost. 118 119 checkConsistency(); 106 120 } 107 121 108 122 ArrayInstance::~ArrayInstance() 109 123 { 124 checkConsistency(DestructorConsistencyCheck); 125 110 126 delete m_storage->m_sparseValueMap; 111 127 fastFree(m_storage); … … 210 226 void ArrayInstance::put(ExecState* exec, unsigned i, JSValue* value) 211 227 { 228 checkConsistency(); 229 212 230 unsigned length = m_length; 213 231 if (i >= length) { … … 226 244 storage->m_numValuesInVector += !valueSlot; 227 245 valueSlot = value; 246 checkConsistency(); 228 247 return; 229 248 } … … 251 270 ++storage->m_numValuesInVector; 252 271 storage->m_vector[i] = value; 272 checkConsistency(); 253 273 return; 254 274 } … … 295 315 296 316 m_storage = storage; 317 318 checkConsistency(); 297 319 } 298 320 … … 312 334 bool ArrayInstance::deleteProperty(ExecState* exec, unsigned i) 313 335 { 336 checkConsistency(); 337 314 338 ArrayStorage* storage = m_storage; 315 339 … … 319 343 valueSlot = 0; 320 344 storage->m_numValuesInVector -= hadValue; 345 checkConsistency(); 321 346 return hadValue; 322 347 } … … 327 352 if (it != map->end()) { 328 353 map->remove(it); 354 checkConsistency(); 329 355 return true; 330 356 } … … 332 358 } 333 359 360 checkConsistency(); 361 334 362 if (i > maxArrayIndex) 335 363 return deleteProperty(exec, Identifier::from(i)); … … 341 369 { 342 370 // FIXME: Filling PropertyNameArray with an identifier for every integer 343 // is incredibly inefficient for large arrays. We need a different approach. 371 // is incredibly inefficient for large arrays. We need a different approach, 372 // which almost certainly means a different structure for PropertyNameArray. 344 373 345 374 ArrayStorage* storage = m_storage; … … 386 415 void ArrayInstance::setLength(unsigned newLength) 387 416 { 417 checkConsistency(); 418 388 419 ArrayStorage* storage = m_storage; 389 420 … … 414 445 415 446 m_length = newLength; 447 448 checkConsistency(); 416 449 } 417 450 … … 439 472 } 440 473 474 typedef std::pair<JSValue*, UString> ArrayQSortPair; 475 441 476 static int compareByStringPairForQSort(const void* a, const void* b) 442 477 { 443 const std::pair<JSValue*, UString>* va = static_cast<const std::pair<JSValue*, UString>*>(a);444 const std::pair<JSValue*, UString>* vb = static_cast<const std::pair<JSValue*, UString>*>(b);478 const ArrayQSortPair* va = static_cast<const ArrayQSortPair*>(a); 479 const ArrayQSortPair* vb = static_cast<const ArrayQSortPair*>(b); 445 480 return compare(va->second, vb->second); 446 481 } … … 462 497 // random or otherwise changing results, effectively making compare function inconsistent. 463 498 464 Vector< std::pair<JSValue*, UString>> values(lengthNotIncludingUndefined);499 Vector<ArrayQSortPair> values(lengthNotIncludingUndefined); 465 500 if (!values.begin()) { 466 501 exec->setException(Error::create(exec, GeneralError, "Out of memory")); … … 472 507 ASSERT(!value->isUndefined()); 473 508 values[i].first = value; 474 values[i].second = value->toString(exec); 475 } 509 } 510 511 // FIXME: While calling these toString functions, the array could be mutated. 512 // In that case, objects pointed to by values in this vector might get garbage-collected! 513 514 // FIXME: The following loop continues to call toString on subsequent values even after 515 // a toString call raises an exception. 516 517 for (size_t i = 0; i < lengthNotIncludingUndefined; i++) 518 values[i].second = values[i].first->toString(exec); 476 519 477 520 if (exec->hadException()) … … 482 525 483 526 #if HAVE(MERGESORT) 484 mergesort(values.begin(), values.size(), sizeof( std::pair<JSValue*, UString>), compareByStringPairForQSort);527 mergesort(values.begin(), values.size(), sizeof(ArrayQSortPair), compareByStringPairForQSort); 485 528 #else 486 // FIXME: QSort may not be stable in some implementations. ECMAScript-262 does not require this, but in practice, browsers perform stable sort. 487 qsort(values.begin(), values.size(), sizeof(std::pair<JSValue*, UString>), compareByStringPairForQSort); 529 // FIXME: The qsort library function is likely to not be a stable sort. 530 // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort. 531 qsort(values.begin(), values.size(), sizeof(ArrayQSortPair), compareByStringPairForQSort); 488 532 #endif 533 534 // FIXME: If the toString function changed the length of the array, this might be 535 // modifying the vector incorrectly. 489 536 490 537 for (size_t i = 0; i < lengthNotIncludingUndefined; i++) 491 538 m_storage->m_vector[i] = values[i].first; 539 540 checkConsistency(SortConsistencyCheck); 492 541 } 493 542 … … 559 608 void ArrayInstance::sort(ExecState* exec, JSObject* compareFunction) 560 609 { 610 checkConsistency(); 611 612 // FIXME: This ignores exceptions raised in the compare function or in toNumber. 613 561 614 // The maximum tree depth is compiled in - but the caller is clearly up to no good 562 615 // if a larger array is passed. … … 580 633 return; 581 634 } 635 636 // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified 637 // right out from under us while we're building the tree here. 582 638 583 639 unsigned numDefined = 0; … … 628 684 ASSERT(tree.abstractor().m_nodes.size() >= numDefined); 629 685 686 // FIXME: If the compare function changed the length of the array, the following might be 687 // modifying the vector incorrectly. 688 630 689 // Copy the values back into m_storage. 631 690 AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter; … … 643 702 for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) 644 703 m_storage->m_vector[i] = 0; 704 705 m_storage->m_numValuesInVector = newUsedVectorLength; 706 707 checkConsistency(SortConsistencyCheck); 645 708 } 646 709 647 710 unsigned ArrayInstance::compactForSorting() 648 711 { 712 checkConsistency(); 713 649 714 ArrayStorage* storage = m_storage; 650 715 … … 691 756 storage->m_vector[i] = 0; 692 757 758 storage->m_numValuesInVector = newUsedVectorLength; 759 760 checkConsistency(SortConsistencyCheck); 761 693 762 return numDefined; 694 763 } … … 704 773 } 705 774 706 } 775 #if CHECK_ARRAY_CONSISTENCY 776 777 void ArrayInstance::checkConsistency(ConsistencyCheckType type) 778 { 779 ASSERT(m_storage); 780 if (type == SortConsistencyCheck) 781 ASSERT(!m_storage->m_sparseValueMap); 782 783 unsigned numValuesInVector = 0; 784 for (unsigned i = 0; i < m_vectorLength; ++i) { 785 if (JSValue* value = m_storage->m_vector[i]) { 786 ASSERT(i < m_length); 787 if (type != DestructorConsistencyCheck) 788 value->type(); // Likely to crash if the object was deallocated. 789 ++numValuesInVector; 790 } else { 791 if (type == SortConsistencyCheck) 792 ASSERT(i >= m_storage->m_numValuesInVector); 793 } 794 } 795 ASSERT(numValuesInVector == m_storage->m_numValuesInVector); 796 797 if (m_storage->m_sparseValueMap) { 798 SparseArrayValueMap::iterator end = m_storage->m_sparseValueMap->end(); 799 for (SparseArrayValueMap::iterator it = m_storage->m_sparseValueMap->begin(); it != end; ++it) { 800 unsigned index = it->first; 801 ASSERT(index < m_length); 802 ASSERT(index >= m_vectorLength); 803 ASSERT(index <= maxArrayIndex); 804 ASSERT(it->second); 805 if (type != DestructorConsistencyCheck) 806 it->second->type(); // Likely to crash if the object was deallocated. 807 } 808 } 809 } 810 811 #endif 812 813 } -
trunk/JavaScriptCore/kjs/array_instance.h
r34355 r34496 2 2 /* 3 3 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 4 * Copyright (C) 2003, 2007 Apple Inc. All rights reserved.4 * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved. 5 5 * 6 6 * This library is free software; you can redistribute it and/or … … 65 65 bool increaseVectorLength(unsigned newLength); 66 66 67 unsigned compactForSorting(); 67 unsigned compactForSorting(); 68 69 enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck }; 70 void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck); 68 71 69 72 unsigned m_length;
Note:
See TracChangeset
for help on using the changeset viewer.