Changeset 34659 in webkit for trunk/JavaScriptCore/kjs/collector.cpp
- Timestamp:
- Jun 19, 2008, 10:29:29 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/collector.cpp
r34597 r34659 1 1 /* 2 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2007 Eric Seidel <[email protected]> 4 4 * … … 36 36 #if USE(MULTIPLE_THREADS) 37 37 #include <pthread.h> 38 #include <wtf/Threading.h> 38 39 #endif 39 40 … … 80 81 81 82 const size_t SPARE_EMPTY_BLOCKS = 2; 82 const size_t MIN_ARRAY_SIZE = 14;83 83 const size_t GROWTH_FACTOR = 2; 84 84 const size_t LOW_WATER_FACTOR = 4; 85 85 const size_t ALLOCATIONS_PER_COLLECTION = 4000; 86 87 static CollectorHeap primaryHeap = { 0, 0, 0, 0, 0, 0, 0, NoOperation }; 88 static CollectorHeap numberHeap = { 0, 0, 0, 0, 0, 0, 0, NoOperation }; 89 90 size_t Collector::mainThreadOnlyObjectCount = 0; 91 HashSet<ArgList*>* Collector::m_markListSet; 92 93 static CollectorBlock* allocateBlock() 86 // This value has to be a macro to be used in max() without introducing 87 // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>. 88 #define MIN_ARRAY_SIZE 14UL 89 90 Heap::Heap() 91 : m_pagesize(getpagesize()) 92 , mainThreadOnlyObjectCount(0) 93 , m_markListSet(0) 94 { 95 memset(&primaryHeap, 0, sizeof(CollectorHeap)); 96 memset(&numberHeap, 0, sizeof(CollectorHeap)); 97 } 98 99 static NEVER_INLINE CollectorBlock* allocateBlock() 94 100 { 95 101 #if PLATFORM(DARWIN) … … 104 110 memset(address, 0, BLOCK_SIZE); 105 111 #else 106 static size_t pagesize = getpagesize();107 112 108 113 size_t extra = 0; 109 if (BLOCK_SIZE > pagesize)110 extra = BLOCK_SIZE - pagesize;114 if (BLOCK_SIZE > m_pagesize) 115 extra = BLOCK_SIZE - m_pagesize; 111 116 112 117 void* mmapResult = mmap(NULL, BLOCK_SIZE + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); … … 139 144 free(block); 140 145 #else 141 munmap(reinterpret_cast<char 142 #endif 143 } 144 145 void Collector::recordExtraCost(size_t cost)146 munmap(reinterpret_cast<char*>(block), BLOCK_SIZE); 147 #endif 148 } 149 150 void Heap::recordExtraCost(size_t cost) 146 151 { 147 152 // Our frequency of garbage collection tries to balance memory use against speed … … 160 165 } 161 166 162 template < Collector::HeapType heapType> struct HeapConstants;163 164 template <> struct HeapConstants< Collector::PrimaryHeap> {167 template <Heap::HeapType heapType> struct HeapConstants; 168 169 template <> struct HeapConstants<Heap::PrimaryHeap> { 165 170 static const size_t cellSize = CELL_SIZE; 166 171 static const size_t cellsPerBlock = CELLS_PER_BLOCK; … … 170 175 }; 171 176 172 template <> struct HeapConstants< Collector::NumberHeap> {177 template <> struct HeapConstants<Heap::NumberHeap> { 173 178 static const size_t cellSize = SMALL_CELL_SIZE; 174 179 static const size_t cellsPerBlock = SMALL_CELLS_PER_BLOCK; … … 178 183 }; 179 184 180 template < Collector::HeapType heapType> ALWAYS_INLINE void* Collector::heapAllocate(size_t s)185 template <Heap::HeapType heapType> ALWAYS_INLINE void* Heap::heapAllocate(size_t s) 181 186 { 182 187 typedef typename HeapConstants<heapType>::Block Block; … … 268 273 targetBlock = (Block*)allocateBlock(); 269 274 targetBlock->freeList = targetBlock->cells; 275 targetBlock->heap = this; 270 276 targetBlockUsedCells = 0; 271 277 heap.blocks[usedBlocks] = (CollectorBlock*)targetBlock; … … 291 297 } 292 298 293 #ifndef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE 294 void* Collector::allocate(size_t s) 299 void* Heap::allocate(size_t s) 295 300 { 296 301 return heapAllocate<PrimaryHeap>(s); 297 302 } 298 #endif 299 300 void* Collector::allocateNumber(size_t s) 303 304 void* Heap::allocateNumber(size_t s) 301 305 { 302 306 return heapAllocate<NumberHeap>(s); … … 363 367 #endif 364 368 365 void Collector::registerAsMainThread()369 void Heap::registerAsMainThread() 366 370 { 367 371 #if USE(MULTIPLE_THREADS) … … 405 409 } 406 410 407 class Collector::Thread {411 class Heap::Thread { 408 412 public: 409 413 Thread(pthread_t pthread, const PlatformThread& platThread, void* base) … … 422 426 pthread_key_t registeredThreadKey; 423 427 pthread_once_t registeredThreadKeyOnce = PTHREAD_ONCE_INIT; 424 Collector::Thread* registeredThreads;428 Heap::Thread* registeredThreads; 425 429 426 430 static void destroyRegisteredThread(void* data) 427 431 { 428 Collector::Thread* thread = (Collector::Thread*)data;432 Heap::Thread* thread = (Heap::Thread*)data; 429 433 430 434 // Can't use JSLock convenience object here because we don't want to re-register … … 435 439 registeredThreads = registeredThreads->next; 436 440 } else { 437 Collector::Thread* last = registeredThreads;438 Collector::Thread* t;441 Heap::Thread* last = registeredThreads; 442 Heap::Thread* t; 439 443 for (t = registeredThreads->next; t != NULL; t = t->next) { 440 444 if (t == thread) { … … 457 461 } 458 462 459 void Collector::registerThread()463 void Heap::registerThread() 460 464 { 461 465 ASSERT(JSLock::lockCount() > 0); … … 465 469 466 470 if (!pthread_getspecific(registeredThreadKey)) { 467 #if PLATFORM(DARWIN) 468 if (onMainThread()) 469 CollectorHeapIntrospector::init(&primaryHeap, &numberHeap); 470 #endif 471 472 Collector::Thread* thread = new Collector::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase()); 471 Heap::Thread* thread = new Heap::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase()); 473 472 474 473 thread->next = registeredThreads; … … 478 477 } 479 478 479 void Heap::initializeHeapIntrospector() 480 { 481 ASSERT(pthread_main_np()); 482 CollectorHeapIntrospector::init(&primaryHeap, &numberHeap); 483 } 484 480 485 #endif 481 486 … … 485 490 #define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0) 486 491 487 void Collector::markStackObjectsConservatively(void* start, void* end)492 void Heap::markStackObjectsConservatively(void* start, void* end) 488 493 { 489 494 if (start > end) { … … 517 522 for (size_t block = 0; block < usedNumberBlocks; block++) { 518 523 if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { 519 Collector::markCell(reinterpret_cast<JSCell*>(xAsBits));524 Heap::markCell(reinterpret_cast<JSCell*>(xAsBits)); 520 525 goto endMarkLoop; 521 526 } … … 539 544 } 540 545 541 void NEVER_INLINE Collector::markCurrentThreadConservativelyInternal()546 void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal() 542 547 { 543 548 void* dummy; … … 547 552 } 548 553 549 void Collector::markCurrentThreadConservatively()554 void Heap::markCurrentThreadConservatively() 550 555 { 551 556 // setjmp forces volatile registers onto the stack … … 692 697 } 693 698 694 void Collector::markOtherThreadConservatively(Thread* thread) 695 { 699 void Heap::markOtherThreadConservatively(Thread* thread) 700 { 701 ASSERT(this == JSGlobalData::sharedInstance().heap); 702 696 703 suspendThread(thread->platformThread); 697 704 … … 710 717 #endif 711 718 712 void Collector::markStackObjectsConservatively()719 void Heap::markStackObjectsConservatively() 713 720 { 714 721 markCurrentThreadConservatively(); 715 722 716 723 #if USE(MULTIPLE_THREADS) 717 for (Thread* thread = registeredThreads; thread != NULL; thread = thread->next) { 718 if (!pthread_equal(thread->posixThread, pthread_self())) { 719 markOtherThreadConservatively(thread); 724 725 if (this == JSGlobalData::sharedInstance().heap) { 726 727 #ifndef NDEBUG 728 // Forbid malloc during the mark phase. Marking a thread suspends it, so 729 // a malloc inside mark() would risk a deadlock with a thread that had been 730 // suspended while holding the malloc lock. 731 fastMallocForbid(); 732 #endif 733 for (Thread* thread = registeredThreads; thread != NULL; thread = thread->next) { 734 if (!pthread_equal(thread->posixThread, pthread_self())) 735 markOtherThreadConservatively(thread); 720 736 } 721 } 722 #endif 723 } 724 725 typedef HashCountedSet<JSCell*> ProtectCountSet; 726 727 static ProtectCountSet& protectedValues() 728 { 729 static ProtectCountSet staticProtectCountSet; 730 return staticProtectCountSet; 731 } 732 733 void Collector::protect(JSValue* k) 737 #ifndef NDEBUG 738 fastMallocAllow(); 739 #endif 740 } 741 #endif 742 } 743 744 void Heap::protect(JSValue* k) 734 745 { 735 746 ASSERT(k); … … 740 751 return; 741 752 742 protectedValues ().add(k->asCell());743 } 744 745 void Collector::unprotect(JSValue* k)753 protectedValues.add(k->asCell()); 754 } 755 756 void Heap::unprotect(JSValue* k) 746 757 { 747 758 ASSERT(k); … … 752 763 return; 753 764 754 protectedValues ().remove(k->asCell());755 } 756 757 void Collector::collectOnMainThreadOnly(JSValue* value)765 protectedValues.remove(k->asCell()); 766 } 767 768 void Heap::collectOnMainThreadOnly(JSValue* value) 758 769 { 759 770 ASSERT(value); … … 769 780 } 770 781 771 void Collector::markProtectedObjects() 772 { 773 ProtectCountSet& protectedValues = KJS::protectedValues(); 782 Heap* Heap::heap(const JSValue* v) 783 { 784 if (JSImmediate::isImmediate(v)) 785 return 0; 786 return Heap::cellBlock(v->asCell())->heap; 787 } 788 789 void Heap::markProtectedObjects() 790 { 774 791 ProtectCountSet::iterator end = protectedValues.end(); 775 792 for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it) { … … 780 797 } 781 798 782 void Collector::markMainThreadOnlyObjects()799 void Heap::markMainThreadOnlyObjects() 783 800 { 784 801 #if USE(MULTIPLE_THREADS) … … 822 839 } 823 840 824 template < Collector::HeapType heapType> size_t Collector::sweep(bool currentThreadIsMainThread)841 template <Heap::HeapType heapType> size_t Heap::sweep(bool currentThreadIsMainThread) 825 842 { 826 843 typedef typename HeapConstants<heapType>::Block Block; … … 829 846 UNUSED_PARAM(currentThreadIsMainThread); // currentThreadIsMainThread is only used in ASSERTs 830 847 // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else 831 CollectorHeap& heap = heapType == Collector::PrimaryHeap ? primaryHeap : numberHeap;848 CollectorHeap& heap = heapType == Heap::PrimaryHeap ? primaryHeap : numberHeap; 832 849 833 850 size_t emptyBlocks = 0; … … 846 863 Cell* cell = curBlock->cells + i; 847 864 848 if (heapType != Collector::NumberHeap) {865 if (heapType != Heap::NumberHeap) { 849 866 JSCell* imp = reinterpret_cast<JSCell*>(cell); 850 867 // special case for allocated but uninitialized object … … 857 874 if (curBlock->collectOnMainThreadOnly.get(i)) { 858 875 curBlock->collectOnMainThreadOnly.clear(i); 859 -- Collector::mainThreadOnlyObjectCount;876 --mainThreadOnlyObjectCount; 860 877 } 861 878 imp->~JSCell(); … … 879 896 } else { 880 897 if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) { 881 if (heapType != Collector::NumberHeap) {898 if (heapType != Heap::NumberHeap) { 882 899 JSCell* imp = reinterpret_cast<JSCell*>(cell); 883 900 ASSERT(currentThreadIsMainThread || !curBlock->collectOnMainThreadOnly.get(i)); 884 901 if (curBlock->collectOnMainThreadOnly.get(i)) { 885 902 curBlock->collectOnMainThreadOnly.clear(i); 886 -- Collector::mainThreadOnlyObjectCount;903 --mainThreadOnlyObjectCount; 887 904 } 888 905 imp->~JSCell(); … … 932 949 } 933 950 934 bool Collector::collect() 935 { 936 ASSERT(JSLock::lockCount() > 0); 937 ASSERT(JSLock::currentThreadIsHoldingLock()); 951 bool Heap::collect() 952 { 953 #ifndef NDEBUG 954 if (JSGlobalData::sharedInstance().heap == this) { 955 ASSERT(JSLock::lockCount() > 0); 956 ASSERT(JSLock::currentThreadIsHoldingLock()); 957 } 958 #endif 938 959 939 960 ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation)); … … 947 968 948 969 // MARK: first mark all referenced objects recursively starting out from the set of root objects 949 950 #ifndef NDEBUG951 // Forbid malloc during the mark phase. Marking a thread suspends it, so952 // a malloc inside mark() would risk a deadlock with a thread that had been953 // suspended while holding the malloc lock.954 fastMallocForbid();955 #endif956 970 957 971 markStackObjectsConservatively(); … … 964 978 #endif 965 979 966 #ifndef NDEBUG967 fastMallocAllow();968 #endif969 970 980 size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects; 971 981 size_t numLiveObjects = sweep<PrimaryHeap>(currentThreadIsMainThread); … … 978 988 } 979 989 980 size_t Collector::size()990 size_t Heap::size() 981 991 { 982 992 return primaryHeap.numLiveObjects + numberHeap.numLiveObjects; 983 993 } 984 994 985 size_t Collector::globalObjectCount()995 size_t Heap::globalObjectCount() 986 996 { 987 997 size_t count = 0; … … 996 1006 } 997 1007 998 size_t Collector::protectedGlobalObjectCount()1008 size_t Heap::protectedGlobalObjectCount() 999 1009 { 1000 1010 size_t count = 0; … … 1002 1012 JSGlobalObject* o = JSGlobalObject::head(); 1003 1013 do { 1004 if (protectedValues ().contains(o))1014 if (protectedValues.contains(o)) 1005 1015 ++count; 1006 1016 o = o->next(); … … 1010 1020 } 1011 1021 1012 size_t Collector::protectedObjectCount()1013 { 1014 return protectedValues ().size();1022 size_t Heap::protectedObjectCount() 1023 { 1024 return protectedValues.size(); 1015 1025 } 1016 1026 … … 1048 1058 } 1049 1059 1050 HashCountedSet<const char*>* Collector::protectedObjectTypeCounts()1060 HashCountedSet<const char*>* Heap::protectedObjectTypeCounts() 1051 1061 { 1052 1062 HashCountedSet<const char*>* counts = new HashCountedSet<const char*>; 1053 1063 1054 ProtectCountSet& protectedValues = KJS::protectedValues();1055 1064 ProtectCountSet::iterator end = protectedValues.end(); 1056 1065 for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it) … … 1060 1069 } 1061 1070 1062 bool Collector::isBusy()1071 bool Heap::isBusy() 1063 1072 { 1064 1073 return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation);
Note:
See TracChangeset
for help on using the changeset viewer.