00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include <stdio.h>
00042
00043 #include <string.h>
00044
00045 #include "MMgc.h"
00046 #include "StaticAssert.h"
00047
00048 #ifdef HAVE_STDARG
00049 #include <stdarg.h>
00050 #endif
00051
00052 #ifdef MEMORY_INFO
00053 #if !defined(__MWERKS__)
00054 #if !defined(__ICC)
00055 #if !defined(UNDER_CE)
00056 #include <typeinfo>
00057 #endif
00058 #endif
00059 #endif
00060 #endif
00061
00062 #ifdef _DEBUG
00063 #include "GCTests.h"
00064 #endif
00065
00066 #ifdef DARWIN
00067 #include <mach/mach_time.h>
00068 #endif
00069
00070
00071 #ifdef WIN32
00072 #include <malloc.h>
00073 #endif
00074
00075 #if defined(_MAC)
00076 #include <alloca.h>
00077 #endif
00078
00079 #ifdef UNIX
00080 #ifdef HAVE_ALLOCA_H
00081 #include <alloca.h>
00082 #else // HAVE_ALLOCA_H
00083 #include <stdlib.h>
00084 #endif // HAVE_ALLOCA_H
00085 #include <sys/time.h>
00086 #endif // UNIX
00087
00088 #if defined(_MAC) && (defined(MMGC_IA32) || defined(MMGC_AMD64))
00089 #include <pthread.h>
00090 #endif
00091
00092 #ifdef HAVE_PTHREAD_H
00093 #include <pthread.h>
00094 #endif // HAVE_PTHREAD_H
00095
00096 #ifdef HAVE_PTHREAD_NP_H
00097 #include <pthread_np.h>
00098 #endif // HAVE_PTHREAD_NP_H
00099
00100 #if defined(_MSC_VER) && defined(_DEBUG)
00101
00102 #pragma warning(disable:4291) // no matching operator delete found; memory will not be freed if initialization throws an exception
00103 #endif
00104
00105 #ifdef FEATURE_SAMPLER
00106
00107 #include "avmplus.h"
00108 #else
00109 #define SAMPLE_FRAME(_x, _s)
00110 #define SAMPLE_CHECK()
00111 #endif
00112
00113 #ifdef SOLARIS
00114 #include <ucontext.h>
00115 #include <sys/frame.h>
00116 #include <errno.h>
00117 #include <unistd.h>
00118 #include <sys/stack.h>
00119 extern "C" greg_t _getsp(void);
00120 #endif
00121
00122
00123
00124
00125 #ifdef WERNER_MODE
00126 #include <typeinfo>
00127 #include <stdio.h>
00128 void *shouldGo;
00129 char statusBuffer[1024];
00130 #endif
00131
00132 namespace MMgc
00133 {
00134
00135 #ifdef MMGC_DRC
00136
00137
00138
00139
00140 const int ZCT::ZCT_REAP_THRESHOLD = 512;
00141
00142
00143 const int ZCT::ZCT_START_SIZE = 1;
00144 #endif
00145
00146 #ifdef MMGC_64BIT
00147 const uintptr MAX_UINTPTR = 0xFFFFFFFFFFFFFFFF;
00148 #else
00149 const uintptr MAX_UINTPTR = 0xFFFFFFFF;
00150 #endif
00151
00152
00153 const bool dumpSizeClassState = false;
00154
00159 const static int kFreeSpaceDivisor = 4;
00160
00161 const static int kMaxIncrement = 4096;
00162
00166 const static uint64 kIncrementalMarkDelayTicks = int(10 * GC::GetPerformanceFrequency() / 1000);
00167
00168 const static uint64 kMarkSweepBurstTicks = 1515909;
00169
00170
00171
00172
00173
00174
00175
00176
00177 const int16 GC::kSizeClasses[kNumSizeClasses] = {
00178 8, 16, 24, 32, 40, 48, 56, 64, 72, 80,
00179 88, 96, 104, 112, 120, 128, 144, 160, 168, 176,
00180 184, 192, 200, 216, 224, 240, 256, 280, 296, 328,
00181 352, 392, 432, 488, 560, 656, 784, 984, 1312, 1968
00182 };
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 const uint8 GC::kSizeClassIndex[246] = {
00193 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
00194 10, 11, 12, 13, 14, 15, 16, 16, 17, 17,
00195 18, 19, 20, 21, 22, 23, 23, 24, 25, 25,
00196 26, 26, 27, 27, 27, 28, 28, 29, 29, 29,
00197 29, 30, 30, 30, 31, 31, 31, 31, 31, 32,
00198 32, 32, 32, 32, 33, 33, 33, 33, 33, 33,
00199 33, 34, 34, 34, 34, 34, 34, 34, 34, 34,
00200 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
00201 35, 35, 36, 36, 36, 36, 36, 36, 36, 36,
00202 36, 36, 36, 36, 36, 36, 36, 36, 37, 37,
00203 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
00204 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
00205 37, 37, 37, 38, 38, 38, 38, 38, 38, 38,
00206 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
00207 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
00208 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
00209 38, 38, 38, 38, 39, 39, 39, 39, 39, 39,
00210 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
00211 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
00212 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
00213 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
00214 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
00215 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
00216 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
00217 39, 39, 39, 39, 39, 39
00218 };
00219 const size_t kLargestAlloc = 1968;
00220
00221 #ifdef MMGC_THREADSAFE
00222 #define USING_CALLBACK_LIST(gc) GCAcquireSpinlock _cblock((gc)->m_callbackListLock)
00223 #define USING_PAGE_MAP() GCAcquireSpinlock _pmlock(pageMapLock)
00224 #else
00225 #define USING_CALLBACK_LIST(gc) ((gc)->CheckThread())
00226 #define USING_PAGE_MAP() ((void) 0)
00227 #endif
00228
00229 GC::GC(GCHeap *gcheap)
00230 :
00231 #ifdef MMGC_DRC
00232 zct(),
00233 #endif
00234 nogc(false),
00235 greedy(false),
00236 findUnmarkedPointers(false),
00237 validateDefRef(false),
00238 keepDRCHistory(false),
00239 gcstats(false),
00240 #ifdef WRITE_BARRIERS
00241 incremental(true),
00242 #else
00243 incremental(false),
00244 #endif
00245 incrementalValidation(false),
00246 #ifdef _DEBUG
00247
00248 incrementalValidationPedantic(false),
00249 #endif
00250
00251 marking(false),
00252 memStart(MAX_UINTPTR),
00253 memEnd(0),
00254 heap(gcheap),
00255 allocsSinceCollect(0),
00256 collecting(false),
00257 m_roots(0),
00258 m_callbacks(0),
00259 markTicks(0),
00260 bytesMarked(0),
00261 markIncrements(0),
00262 marks(0),
00263 sweeps(0),
00264 totalGCPages(0),
00265 stackCleaned(true),
00266 rememberedStackTop(0),
00267 destroying(false),
00268 lastMarkTicks(0),
00269 lastSweepTicks(0),
00270 lastStartMarkIncrementCount(0),
00271 t0(GetPerformanceCounter()),
00272 dontAddToZCTDuringCollection(false),
00273 numObjects(0),
00274 hitZeroObjects(false),
00275 smallEmptyPageList(NULL),
00276 largeEmptyPageList(NULL),
00277 sweepStart(0),
00278 heapSizeAtLastAlloc(gcheap->GetTotalHeapSize()),
00279 finalizedValue(true),
00280
00281 collectThreshold(256),
00282 #if MMGC_THREADSAFE
00283 m_exclusiveGCThread(NULL),
00284 m_gcRunning(false),
00285 m_condDone(m_lock),
00286 m_requestCount(0),
00287 m_condNoRequests(m_lock)
00288 #else
00289 disableThreadCheck(false)
00290 #endif
00291 {
00292
00293 MMGC_STATIC_ASSERT(sizeof(int8) == 1);
00294 MMGC_STATIC_ASSERT(sizeof(uint8) == 1);
00295 MMGC_STATIC_ASSERT(sizeof(int16) == 2);
00296 MMGC_STATIC_ASSERT(sizeof(uint16) == 2);
00297 MMGC_STATIC_ASSERT(sizeof(int32) == 4);
00298 MMGC_STATIC_ASSERT(sizeof(uint32) == 4);
00299 MMGC_STATIC_ASSERT(sizeof(int64) == 8);
00300 MMGC_STATIC_ASSERT(sizeof(uint64) == 8);
00301 MMGC_STATIC_ASSERT(sizeof(sintptr) == sizeof(void *));
00302 MMGC_STATIC_ASSERT(sizeof(uintptr) == sizeof(void *));
00303 #ifdef MMGC_64BIT
00304 MMGC_STATIC_ASSERT(sizeof(sintptr) == 8);
00305 MMGC_STATIC_ASSERT(sizeof(uintptr) == 8);
00306 #else
00307 MMGC_STATIC_ASSERT(sizeof(sintptr) == 4);
00308 MMGC_STATIC_ASSERT(sizeof(uintptr) == 4);
00309 #endif
00310
00311 {
00312 GCWorkItem item;
00313 MMGC_GET_STACK_EXTENTS(this, item.ptr, item._size);
00314 rememberedStackBottom = (const void *)((const char *)item.ptr + item._size);
00315 }
00316
00317 #ifdef MMGC_DRC
00318 zct.SetGC(this);
00319 #endif
00320
00321
00322
00323 for (int i=0; i<kNumSizeClasses; i++) {
00324 containsPointersAllocs[i] = new GCAlloc(this, kSizeClasses[i], true, false, i);
00325 #ifdef MMGC_DRC
00326 containsPointersRCAllocs[i] = new GCAlloc(this, kSizeClasses[i], true, true, i);
00327 #endif
00328 noPointersAllocs[i] = new GCAlloc(this, kSizeClasses[i], false, false, i);
00329 }
00330
00331 largeAlloc = new GCLargeAlloc(this);
00332
00333 pageMap = (unsigned char*) heapAlloc(1);
00334
00335 memset(m_bitsFreelists, 0, sizeof(uint32*) * kNumSizeClasses);
00336 m_bitsNext = (uint32*)heapAlloc(1);
00337
00338
00339 GCAssert(offsetof(GCLargeAlloc::LargeBlock, next) == offsetof(GCAlloc::GCBlock, next));
00340
00341
00342 for(int i=0; i<GCV_COUNT; i++)
00343 {
00344 SetGCContextVariable(i, NULL);
00345 }
00346
00347 #ifdef _DEBUG
00348
00349
00350 incrementalValidation = true;
00351 #ifdef WIN32
00352 m_gcThread = GetCurrentThreadId();
00353 #endif
00354 #endif
00355
00356
00357 GCAssert(offsetof(GCLargeAlloc::LargeBlock, usableSize) == offsetof(GCAlloc::GCBlock, size));
00358
00359 #ifndef MMGC_PORTING_API
00360 #ifndef MMGC_ARM // TODO MMGC_ARM
00361 #ifdef _DEBUG
00362 if (!nogc)
00363 RunGCTests(this);
00364 #endif
00365 #endif
00366 #endif
00367
00368
00369 GCAssert(offsetof(GCLargeAlloc::LargeBlock, usableSize) == offsetof(GCAlloc::GCBlock, size));
00370
00371 }
00372
00373 GC::~GC()
00374 {
00375
00376 destroying = true;
00377 ClearMarks();
00378 ForceSweep();
00379
00380
00381
00382 void **pageList = NULL;
00383 for(int i=0, n=kNumSizeClasses; i<n; i++) {
00384 uint32* bitsFreelist = m_bitsFreelists[i];
00385 while(bitsFreelist) {
00386 uint32 *next = *(uint32**)bitsFreelist;
00387 if(((uintptr)bitsFreelist & 0xfff) == 0) {
00388 *((void**)bitsFreelist) = pageList;
00389 pageList = (void**)bitsFreelist;
00390 }
00391 bitsFreelist = next;
00392 }
00393 }
00394
00395
00396 while (pageList) {
00397 void **next = (void**) *pageList;
00398 heap->Free((void*)pageList);
00399 pageList = next;
00400 }
00401
00402 for (int i=0; i < kNumSizeClasses; i++) {
00403 delete containsPointersAllocs[i];
00404 #ifdef MMGC_DRC
00405 delete containsPointersRCAllocs[i];
00406 #endif
00407 delete noPointersAllocs[i];
00408 }
00409
00410 if (largeAlloc) {
00411 delete largeAlloc;
00412 }
00413
00414
00415 pageList = NULL;
00416
00417 heap->Free(pageMap);
00418
00419 #ifndef MMGC_THREADSAFE
00420 CheckThread();
00421 #endif
00422
00423 GCAssert(!m_roots);
00424 GCAssert(!m_callbacks);
00425
00426 {
00427 GCSpinLock lock(m_rootListLock);
00428
00429 while(m_roots) {
00430 m_roots->Destroy();
00431 }
00432 }
00433
00434 while(m_callbacks) {
00435 m_callbacks->Destroy();
00436 }
00437 }
00438
00439 void GC::Collect()
00440 {
00441 CollectWithBookkeeping(false, false);
00442 }
00443
00444 void GC::CollectWithBookkeeping(bool callerHoldsLock,
00445 bool callerHasActiveRequest)
00446 {
00447 #ifdef MMGC_THREADSAFE
00448 GCAssert(callerHoldsLock == m_lock.IsHeld());
00449 #ifdef _DEBUG
00450 GCAssert(callerHasActiveRequest == GCThread::GetCurrentThread()->IsInActiveRequest());
00451 #endif
00452 #else
00453 (void) callerHoldsLock;
00454 (void) callerHasActiveRequest;
00455 CheckThread();
00456 #endif
00457
00458 #ifdef MMGC_THREADSAFE
00459 if (!callerHoldsLock)
00460 m_lock.Acquire();
00461
00462 if (nogc || m_gcRunning || zct.reaping) {
00463 if (!callerHoldsLock)
00464 m_lock.Release();
00465 return;
00466 }
00467 #else
00468 if (nogc || collecting || zct.reaping) {
00469 return;
00470 }
00471 #endif
00472
00473 #ifdef MMGC_THREADSAFE
00474 GCThread *thisThread = GCThread::GetCurrentThread();
00475 if (m_exclusiveGCThread != NULL) {
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485 if (m_exclusiveGCThread != thisThread) {
00486 GCRoot *stackRoot;
00487 void *stack;
00488 size_t stackSize;
00489
00490
00491
00492
00493
00494 MMGC_GET_STACK_EXTENTS(this, stack, stackSize);
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 if (callerHasActiveRequest) {
00506 stackRoot = new GCRoot(this, stack, stackSize);
00507
00508 OnLeaveRequestAlreadyLocked();
00509 }
00510
00511 while (m_exclusiveGCThread != NULL)
00512 m_condDone.Wait();
00513
00514 if (callerHasActiveRequest) {
00515
00516 delete stackRoot;
00517 OnEnterRequestAlreadyLocked();
00518 }
00519 }
00520
00521 if (!callerHoldsLock)
00522 m_lock.Release();
00523 return;
00524 }
00525
00526
00527 m_exclusiveGCThread = thisThread;
00528 if (callerHasActiveRequest) {
00529
00530 OnLeaveRequestAlreadyLocked();
00531 }
00532
00533
00534 while (m_requestCount > 0)
00535 m_condNoRequests.Wait();
00536
00537
00538
00539 GCAssert(m_requestCount == 0);
00540 GCAssert(m_exclusiveGCThread == thisThread);
00541
00542
00543 m_gcRunning = true;
00544 #endif
00545
00546 {
00547 USING_CALLBACK_LIST(this);
00548 for (GCCallback *cb = m_callbacks; cb; cb = cb->nextCB)
00549 cb->enterExclusiveGC();
00550 }
00551
00552 #ifdef MMGC_THREADSAFE
00553 m_lock.Release();
00554 #endif
00555
00556 {
00557 USING_CALLBACK_LIST(this);
00558 for (GCCallback *cb = m_callbacks; cb; cb = cb->nextCB)
00559 cb->enterExclusiveGCNoLock();
00560 }
00561
00562 CollectImpl();
00563
00564 #ifdef MMGC_THREADSAFE
00565 m_lock.Acquire();
00566
00567
00568
00569 GCAssert(m_requestCount == 0);
00570 GCAssert(m_exclusiveGCThread == thisThread);
00571 #endif
00572
00573 {
00574 USING_CALLBACK_LIST(this);
00575 for (GCCallback *cb = m_callbacks; cb; cb = cb->nextCB)
00576 cb->leaveExclusiveGC();
00577 }
00578
00579 #ifdef MMGC_THREADSAFE
00580
00581 m_gcRunning = false;
00582
00583 m_exclusiveGCThread = NULL;
00584 if (callerHasActiveRequest)
00585 OnEnterRequestAlreadyLocked();
00586
00587 m_condDone.NotifyAll();
00588
00589 if (!callerHoldsLock)
00590 m_lock.Release();
00591 #endif
00592 }
00593
00594 void GC::CollectImpl()
00595 {
00596 #ifndef MMGC_THREADSAFE
00597 ReapZCT();
00598 #endif
00599
00600 if(!marking)
00601 StartIncrementalMark();
00602 if(marking)
00603 FinishIncrementalMark();
00604
00605 #ifdef _DEBUG
00606
00607
00608
00609
00610 FindUnmarkedPointers();
00611 #endif
00612 }
00613
00614 #ifdef _DEBUG
00615 void GC::Trace(const void *stackStart, uint32 stackSize)
00616 {
00617 MMGC_ASSERT_EXCLUSIVE_GC(this);
00618
00619 SAMPLE_FRAME("[mark]", core());
00620
00621
00622 ClearMarks();
00623
00624 SAMPLE_CHECK();
00625
00626 GCStack<GCWorkItem> work;
00627 {
00628 #ifdef GCHEAP_LOCK
00629 GCAcquireSpinlock lock(m_rootListLock);
00630 #endif
00631 GCRoot *r = m_roots;
00632 while(r) {
00633 GCWorkItem item = r->GetWorkItem();
00634 MarkItem(item, work);
00635 r = r->next;
00636 }
00637 }
00638
00639 SAMPLE_CHECK();
00640
00641 if(stackStart == NULL) {
00642 MarkQueueAndStack(work);
00643 } else {
00644 GCWorkItem item(stackStart, stackSize, false);
00645 PushWorkItem(work, item);
00646 Mark(work);
00647 }
00648
00649 SAMPLE_CHECK();
00650
00651 ClearMarks();
00652 }
00653 #endif
00654
00655 void *GC::Alloc(size_t size, int flags)
00656 {
00657 #ifdef MMGC_THREADSAFE
00658 GCAutoLock _lock(m_lock);
00659 GCAssert(!m_gcRunning);
00660 #else
00661 CheckThread();
00662 #endif
00663 return AllocAlreadyLocked(size, flags);
00664 }
00665
00666 void *GC::AllocAlreadyLocked(size_t size, int flags)
00667 {
00668 #ifdef FEATURE_SAMPLER
00669 avmplus::AvmCore *core = (avmplus::AvmCore*)GetGCContextVariable(GCV_AVMCORE);
00670 if(core)
00671 core->sampleCheck();
00672 #endif
00673 GCAssertMsg(size > 0, "cannot allocate a 0 sized block\n");
00674
00675 #ifdef _DEBUG
00676 GCAssert(size + 7 > size);
00677 if (GC::greedy) {
00678 CollectWithBookkeeping(true, true);
00679 }
00680
00681 if(incrementalValidationPedantic) {
00682 if(!marking)
00683 StartIncrementalMark();
00684 }
00685 #endif
00686
00687
00688 if(size+7 < size)
00689 return NULL;
00690
00691 size = (size+7)&~7;
00692
00693 size += DebugSize();
00694
00695 GCAssertMsg(size > 0, "debug overflow, adding space for Debug stuff overflowed size_t\n");
00696
00697 GCAlloc **allocs = noPointersAllocs;
00698 #ifdef MMGC_DRC
00699 if(flags & kRCObject) {
00700 allocs = containsPointersRCAllocs;
00701 } else
00702 #endif
00703 if(flags & kContainsPointers) {
00704 allocs = containsPointersAllocs;
00705 }
00706
00707 void *item;
00708
00709 if (size <= 128) {
00710 GCAlloc *b = (GCAlloc*)allocs[(size >> 3) - 1];
00711 GCAssert(size <= b->GetItemSize());
00712 item = b->Alloc(size, flags);
00713 } else if (size <= kLargestAlloc) {
00714
00715
00716 unsigned index = kSizeClassIndex[(size>>3)-1];
00717
00718
00719 GCAssert(size <= allocs[index]->GetItemSize());
00720
00721
00722 GCAssert(size > allocs[index-1]->GetItemSize());
00723
00724 item = allocs[index]->Alloc(size, flags);
00725 } else {
00726 item = largeAlloc->Alloc(size, flags);
00727 }
00728
00729 #ifdef MEMORY_INFO
00730 if(item)
00731 item = DebugDecorate(item, GC::Size(GetUserPointer(item)) + DebugSize(), 3);
00732 #endif
00733
00734 #ifdef _DEBUG
00735 bool shouldZero = (flags & kZero) || incrementalValidationPedantic;
00736
00737
00738
00739
00740
00741
00742
00743 if((item) && (shouldZero)) {
00744 memset(item, 0, Size(item));
00745 }
00746 #endif
00747
00748 SAMPLE_ALLOC(item, GC::Size(item));
00749
00750 return item;
00751 }
00752
00753 void GC::MaybeGC(bool callerHasActiveRequest)
00754 {
00755 if (greedy) {
00756 CollectWithBookkeeping(false, callerHasActiveRequest);
00757 } else if (marking) {
00758 IncrementalMark();
00759 } else {
00760 #ifdef MMGC_THREADSAFE
00761 GCAutoLock _lock(m_lock);
00762 #endif
00763
00764
00765 uint64 now = GetPerformanceCounter();
00766 if (now - lastSweepTicks <= kMarkSweepBurstTicks)
00767 return;
00768
00769
00770
00771
00772 bool force = (heapSizeAtLastAlloc > collectThreshold &&
00773 heapSizeAtLastAlloc < heap->GetTotalHeapSize());
00774
00775 if (incremental) {
00776 if (force || (totalGCPages > collectThreshold &&
00777 allocsSinceCollect * kFreeSpaceDivisor >= totalGCPages)) {
00778 StartIncrementalMark();
00779 }
00780 } else {
00781
00782
00783 if (force || heap->GetFreeHeapSize() == 0)
00784 CollectWithBookkeeping(true, callerHasActiveRequest);
00785 }
00786 }
00787 }
00788
00789 void *GC::Calloc(size_t num, size_t elsize, int flags)
00790 {
00791 uint64 size = (uint64)num * (uint64)elsize;
00792 if(size > 0xfffffff0)
00793 {
00794 GCAssertMsg(false, "Attempted allocation overflows size_t\n");
00795 return NULL;
00796 }
00797 return Alloc(num * elsize, flags);
00798 }
00799
00800 void GC::Free(const void *item)
00801 {
00802 #ifdef MMGC_THREADSAFE
00803 GCAutoLock _lock(m_lock);
00804 GCAssert(!m_gcRunning);
00805 #else
00806 CheckThread();
00807 #endif
00808
00809 if(item == NULL) {
00810 return;
00811 }
00812
00813 bool isLarge;
00814
00815 SAMPLE_DEALLOC(GetRealPointer(item), GC::Size(item));
00816
00817
00818
00819 if(collecting) {
00820 goto bail;
00821 }
00822
00823 isLarge = GCLargeAlloc::IsLargeBlock(GetRealPointer(item));
00824
00825 if (marking) {
00826
00827
00828 if(IsQueued(item))
00829 goto bail;
00830 }
00831
00832 #ifdef _DEBUG
00833 #ifdef MMGC_DRC
00834
00835
00836
00837 if(isLarge ? GCLargeAlloc::IsRCObject(item) : GCAlloc::IsRCObject(item))
00838 {
00839 RCObjectZeroCheck((RCObject*)item);
00840 }
00841 #endif // MMGC_DRC
00842 #endif
00843
00844 #ifdef MEMORY_INFO
00845 DebugFree(item, 0xca, 4);
00846 #endif
00847
00848 if (isLarge) {
00849 largeAlloc->Free(GetRealPointer(item));
00850 } else {
00851 GCAlloc::Free(GetRealPointer(item));
00852 }
00853 return;
00854
00855 bail:
00856
00857
00858
00859 if(IsFinalized(item))
00860 ClearFinalized(item);
00861 if(HasWeakRef(item))
00862 ClearWeakRef(item);
00863 }
00864
00865 int GC::GetMark(const void *item)
00866 {
00867 item = GetRealPointer(item);
00868 if (GCLargeAlloc::IsLargeBlock(item)) {
00869 return GCLargeAlloc::GetMark(item);
00870 } else {
00871 return GCAlloc::GetMark(item);
00872 }
00873 }
00874
00875 void GC::ClearMarks()
00876 {
00877 MMGC_ASSERT_EXCLUSIVE_GC(this);
00878
00879 for (int i=0; i < kNumSizeClasses; i++) {
00880 #ifdef MMGC_DRC
00881 containsPointersRCAllocs[i]->ClearMarks();
00882 #endif
00883 containsPointersAllocs[i]->ClearMarks();
00884 noPointersAllocs[i]->ClearMarks();
00885 }
00886 largeAlloc->ClearMarks();
00887 }
00888
00889 void GC::Finalize()
00890 {
00891 MMGC_ASSERT_EXCLUSIVE_GC(this);
00892
00893 for(int i=0; i < kNumSizeClasses; i++) {
00894 #ifdef MMGC_DRC
00895 containsPointersRCAllocs[i]->Finalize();
00896 #endif
00897 containsPointersAllocs[i]->Finalize();
00898 noPointersAllocs[i]->Finalize();
00899 }
00900 largeAlloc->Finalize();
00901 finalizedValue = !finalizedValue;
00902
00903
00904 for(int i=0; i < kNumSizeClasses; i++) {
00905 #ifdef MMGC_DRC
00906 containsPointersRCAllocs[i]->m_finalized = false;
00907 #endif
00908 containsPointersAllocs[i]->m_finalized = false;
00909 noPointersAllocs[i]->m_finalized = false;
00910 }
00911 }
00912
00913 void GC::Sweep(bool force)
00914 {
00915 MMGC_ASSERT_EXCLUSIVE_GC(this);
00916
00917
00918
00919
00920 collecting = true;
00921
00922 SAMPLE_FRAME("[sweep]", core());
00923 sweeps++;
00924
00925 size_t heapSize = heap->GetUsedHeapSize();
00926
00927 #ifdef MEMORY_INFO
00928 if(heap->enableMemoryProfiling) {
00929 GCDebugMsg(false, "Pre sweep memory info:\n");
00930 DumpMemoryInfo();
00931 }
00932 #endif
00933
00934
00935
00936 {
00937 USING_CALLBACK_LIST(this);
00938 GCCallback *cb = m_callbacks;
00939 while(cb) {
00940 cb->presweep();
00941 cb = cb->nextCB;
00942 }
00943 }
00944
00945 SAMPLE_CHECK();
00946
00947
00948 if(!force) {
00949
00950 Mark(m_incrementalWork);
00951 }
00952
00953 Finalize();
00954
00955
00956 if(!force) {
00957
00958 Mark(m_incrementalWork);
00959 }
00960
00961 SAMPLE_CHECK();
00962
00963
00964 GCAlloc::GCBlock *b = smallEmptyPageList;
00965 while(b) {
00966 GCAlloc::GCBlock *next = b->next;
00967 #ifdef _DEBUG
00968 b->alloc->SweepGuts(b);
00969 #endif
00970 b->alloc->FreeChunk(b);
00971 b = next;
00972 }
00973 smallEmptyPageList = NULL;
00974
00975 SAMPLE_CHECK();
00976
00977 GCLargeAlloc::LargeBlock *lb = largeEmptyPageList;
00978 while(lb) {
00979 GCLargeAlloc::LargeBlock *next = lb->next;
00980 #ifdef MEMORY_INFO
00981 DebugFreeReverse(lb+1, 0xba, 3);
00982 #endif
00983
00984 FreeBlock(lb, lb->GetNumBlocks());
00985 lb = next;
00986 }
00987 largeEmptyPageList = NULL;
00988
00989 SAMPLE_CHECK();
00990
00991 #ifdef MEMORY_INFO
00992 if(heap->enableMemoryProfiling) {
00993 GCDebugMsg(false, "Post sweep memory info:\n");
00994 DumpMemoryInfo();
00995 }
00996 #endif
00997
00998
00999 marking = false;
01000 collecting = false;
01001
01002
01003 {
01004 USING_CALLBACK_LIST(this);
01005 GCCallback *cb = m_callbacks;
01006 while(cb) {
01007 cb->postsweep();
01008 cb = cb->nextCB;
01009 }
01010 }
01011
01012 SAMPLE_CHECK();
01013
01014 allocsSinceCollect = 0;
01015 lastSweepTicks = GetPerformanceCounter();
01016
01017 if(GC::gcstats) {
01018 int sweepResults = 0;
01019 GCAlloc::GCBlock *bb = smallEmptyPageList;
01020 while(bb) {
01021 sweepResults++;
01022 bb = bb->next;
01023 }
01024
01025 GCLargeAlloc::LargeBlock *lbb = largeEmptyPageList;
01026 while(lbb) {
01027 sweepResults += lbb->GetNumBlocks();
01028 lbb = lbb->next;
01029 }
01030
01031 sweepResults += int(heapSize - heap->GetUsedHeapSize());
01032 double millis = duration(sweepStart);
01033 gclog("[mem] sweep(%d) reclaimed %d whole pages (%d kb) in %.2f millis (%.4f s)\n",
01034 sweeps, sweepResults, sweepResults*GCHeap::kBlockSize>>10, millis,
01035 duration(t0)/1000);
01036 }
01037 #ifdef DEBUGGER
01038 StopGCActivity();
01039 #endif
01040
01041 #ifdef MEMORY_INFO
01042 m_gcLastStackTrace = GetStackTraceIndex(5);
01043 #endif
01044 }
01045
01046 void* GC::AllocBlock(int size, int pageType, bool zero)
01047 {
01048 MMGC_ASSERT_GC_LOCK(this);
01049 #ifdef DEBUGGER
01050 AllocActivity(size);
01051 #endif
01052 GCAssert(size > 0);
01053
01054
01055
01056
01057 uint64 now = GetPerformanceCounter();
01058 if(!marking && !collecting &&
01059 heapSizeAtLastAlloc > collectThreshold &&
01060 now - lastSweepTicks > kMarkSweepBurstTicks &&
01061 heapSizeAtLastAlloc < heap->GetTotalHeapSize())
01062 {
01063 if(incremental && !nogc)
01064 StartIncrementalMark();
01065 else
01066 CollectWithBookkeeping(true, true);
01067 }
01068
01069 void *item;
01070
01071 if(incremental && !nogc)
01072 item = AllocBlockIncremental(size, zero);
01073 else
01074 item = AllocBlockNonIncremental(size, zero);
01075
01076 if(!item) {
01077 int incr = (int)(size + totalGCPages / kFreeSpaceDivisor);
01078 if(incr > kMaxIncrement) {
01079 incr = size < kMaxIncrement ? kMaxIncrement : size;
01080 }
01081 heap->ExpandHeap(incr);
01082 item = heap->Alloc(size, false);
01083 }
01084
01085 GCAssert(item != NULL);
01086 if (item != NULL)
01087 {
01088 allocsSinceCollect += size;
01089
01090
01091
01092 MarkGCPages(item, 1, pageType);
01093 if(pageType == kGCLargeAllocPageFirst) {
01094 MarkGCPages((char*)item+GCHeap::kBlockSize, size - 1, kGCLargeAllocPageRest);
01095 }
01096 totalGCPages += size;
01097 }
01098
01099
01100 heapSizeAtLastAlloc = heap->GetTotalHeapSize();
01101
01102 return item;
01103 }
01104
01105 void* GC::AllocBlockIncremental(int size, bool zero)
01106 {
01107 MMGC_ASSERT_GC_LOCK(this);
01108
01109 if(!collecting || incrementalValidation) {
01110 uint64 now = GetPerformanceCounter();
01111 if (marking) {
01112 if(now - lastMarkTicks > kIncrementalMarkDelayTicks) {
01113 IncrementalMark();
01114 }
01115 } else if (incrementalValidation ||
01116 (totalGCPages > collectThreshold &&
01117 allocsSinceCollect * kFreeSpaceDivisor >= totalGCPages &&
01118
01119 (now - lastSweepTicks > kMarkSweepBurstTicks))) {
01120 StartIncrementalMark();
01121 }
01122 }
01123
01124 void *item = heap->Alloc(size, false, zero);
01125 if(!item && !collecting) {
01126 if(marking) {
01127 GCAssert(!nogc);
01128 FinishIncrementalMark();
01129 item = heap->Alloc(size, false, zero);
01130 }
01131 }
01132 return item;
01133 }
01134
01135 void* GC::AllocBlockNonIncremental(int size, bool zero)
01136 {
01137 MMGC_ASSERT_GC_LOCK(this);
01138
01139 void *item = heap->Alloc(size, false, zero);
01140 if (!item) {
01141 if (heap->GetTotalHeapSize() >= collectThreshold &&
01142 allocsSinceCollect >= totalGCPages / kFreeSpaceDivisor)
01143 {
01144 CollectWithBookkeeping(true, true);
01145 item = heap->Alloc(size, false, zero);
01146 }
01147 }
01148 return item;
01149 }
01150
01151 void GC::FreeBlock(void *ptr, uint32 size)
01152 {
01153 #ifdef MMGC_THREADSAFE
01154 GCAssert(m_lock.IsHeld() || destroying
01155 || (m_gcRunning
01156 && m_exclusiveGCThread == GCThread::GetCurrentThread()));
01157 #endif
01158 #ifdef DEBUGGER
01159 AllocActivity(- (int)size);
01160 #endif
01161 if(!collecting) {
01162 allocsSinceCollect -= size;
01163 }
01164 totalGCPages -= size;
01165 heap->Free(ptr);
01166 UnmarkGCPages(ptr, size);
01167 }
01168
01169 int GC::GetPageMapValueAlreadyLocked(uintptr addr) const
01170 {
01171 uintptr index = (addr-memStart) >> 12;
01172
01173 #ifdef MMGC_AMD64
01174 GCAssert((index >> 2) < uintptr(64*65536) * uintptr(GCHeap::kBlockSize));
01175 #else
01176 GCAssert(index >> 2 < 64 * GCHeap::kBlockSize);
01177 #endif
01178
01179 uint32 shiftAmount = (index&0x3) * 2;
01180
01181
01182
01183 return (pageMap[index >> 2] >> shiftAmount) & 3;
01184 }
01185
01186 void GC::SetPageMapValue(uintptr addr, int val)
01187 {
01188 uintptr index = (addr-memStart) >> 12;
01189 #ifdef MMGC_AMD64
01190 GCAssert((index >> 2) < uintptr(64*65536) * uintptr(GCHeap::kBlockSize));
01191 #else
01192 GCAssert(index >> 2 < 64 * GCHeap::kBlockSize);
01193 #endif
01194 pageMap[index >> 2] |= (val<<((index&0x3)*2));
01195 }
01196
01197 void GC::ClearPageMapValue(uintptr addr)
01198 {
01199 uintptr index = (addr-memStart) >> 12;
01200 #ifdef MMGC_AMD64
01201 GCAssert((index >> 2) < uintptr(64*65536) * uintptr(GCHeap::kBlockSize));
01202 #else
01203 GCAssert((index >> 2) < 64 * GCHeap::kBlockSize);
01204 #endif
01205 pageMap[index >> 2] &= ~(3<<((index&0x3)*2));
01206 }
01207
01208 void GC::Mark(GCStack<GCWorkItem> &work)
01209 {
01210 MMGC_ASSERT_EXCLUSIVE_GC(this);
01211 while(work.Count()) {
01212 MarkItem(work);
01213 }
01214 }
01215
01216 void GC::MarkGCPages(void *item, uint32 numPages, int to)
01217 {
01218 USING_PAGE_MAP();
01219 uintptr addr = (uintptr)item;
01220 size_t shiftAmount=0;
01221 unsigned char *dst = pageMap;
01222
01223
01224 size_t numBytesToCopy = (memEnd-memStart)>>14;
01225
01226 if(addr < memStart) {
01227
01228
01229 addr &= ~0x3fff;
01230
01231 if(memStart != MAX_UINTPTR) {
01232 shiftAmount = (memStart - addr) >> 14;
01233 }
01234 memStart = addr;
01235 }
01236
01237 if(addr + (numPages+1)*GCHeap::kBlockSize > memEnd) {
01238
01239 memEnd = addr + (numPages+1)*GCHeap::kBlockSize;
01240
01241 memEnd = (memEnd+0x3fff)&~0x3fff;
01242 }
01243
01244 uint32 numPagesNeeded = (uint32)(((memEnd-memStart)>>14)/GCHeap::kBlockSize + 1);
01245 if(numPagesNeeded > heap->Size(pageMap)) {
01246 dst = (unsigned char*)heap->Alloc(numPagesNeeded);
01247 }
01248
01249 if(shiftAmount || dst != pageMap) {
01250 memmove(dst + shiftAmount, pageMap, numBytesToCopy);
01251 memset(dst, 0, shiftAmount);
01252 if(dst != pageMap) {
01253 heap->Free(pageMap);
01254 pageMap = dst;
01255 }
01256 }
01257
01258 addr = (uintptr)item;
01259 while(numPages--)
01260 {
01261 GCAssert(GetPageMapValueAlreadyLocked(addr) == 0);
01262 SetPageMapValue(addr, to);
01263 addr += GCHeap::kBlockSize;
01264 }
01265 }
01266
01267 void GC::UnmarkGCPages(void *item, uint32 numpages)
01268 {
01269 uintptr addr = (uintptr) item;
01270
01271 USING_PAGE_MAP();
01272 while(numpages--)
01273 {
01274 ClearPageMapValue(addr);
01275 addr += GCHeap::kBlockSize;
01276 }
01277 }
01278
01279 void GC::CleanStack(bool force)
01280 {
01281 #if defined(_MSC_VER) && (defined(_DEBUG) || defined(_ARM_))
01282
01283 (void)force;
01284 return;
01285 #else
01286 if(!force && (stackCleaned || rememberedStackTop == 0))
01287 return;
01288
01289 stackCleaned = true;
01290
01291 register void *stackP;
01292
01293 #if defined MMGC_IA32
01294 #ifdef WIN32
01295 __asm {
01296 mov stackP,esp
01297 }
01298 #elif defined SOLARIS
01299 stackP = (void *) _getsp();
01300 #else
01301 asm("movl %%esp,%0" : "=r" (stackP));
01302 #endif
01303 #endif
01304
01305 #if defined MMGC_AMD64
01306 #ifdef WIN32
01307 int foo;
01308 stackP = &foo;
01309 #else
01310 asm("mov %%rsp,%0" : "=r" (stackP));
01311 #endif
01312 #endif
01313
01314 #if defined MMGC_SPARC
01315 stackP = (void *) _getsp();
01316 #endif
01317
01318 #if defined MMGC_PPC
01319
01320 #ifdef _MAC
01321 asm("mr %0,r1" : "=r" (stackP));
01322 #else // _MAC
01323 asm("mr %0,%%r1" : "=r" (stackP));
01324 #endif // _MAC
01325 #endif // MMGC_PPC
01326
01327 if( ((char*) stackP > (char*)rememberedStackTop) && ((char *)rememberedStackBottom > (char*)stackP)) {
01328 size_t amount = (char*) stackP - (char*)rememberedStackTop;
01329 void *stack = alloca(amount);
01330 if(stack) {
01331 memset(stack, 0, amount);
01332 }
01333 }
01334 #endif // __MSC_VER && _DEBUG
01335 }
01336
01337 #if defined(MMGC_PPC) && defined(__GNUC__)
01338 __attribute__((noinline))
01339 #endif
01340 void GC::MarkQueueAndStack(GCStack<GCWorkItem>& work)
01341 {
01342 GCWorkItem item;
01343
01344 MMGC_GET_STACK_EXTENTS(this, item.ptr, item._size);
01345
01346
01347 if(rememberedStackTop == 0 || rememberedStackTop > item.ptr) {
01348 rememberedStackTop = item.ptr;
01349 }
01350
01351 PushWorkItem(work, item);
01352 Mark(work);
01353 }
01354
01355 void GCRoot::init(GC* _gc, const void *_object, size_t _size)
01356 {
01357 #ifndef _DEBUG
01358
01359 if(_object == this) {
01360 size_t s = FixedMalloc::GetInstance()->Size(this);
01361
01362 memset(this, 0, s);
01363 }
01364 #endif
01365 gc = _gc;
01366 object = _object;
01367 size = _size;
01368 gc->AddRoot(this);
01369 }
01370
01371 GCRoot::GCRoot(GC * _gc)
01372 {
01373 init(_gc, this, FixedMalloc::GetInstance()->Size(this));
01374 }
01375
01376 GCRoot::GCRoot(GC * _gc, const void * _object, size_t _size)
01377 {
01378 init(_gc, _object, _size);
01379 }
01380
01381 GCRoot::~GCRoot()
01382 {
01383 if(gc) {
01384 gc->RemoveRoot(this);
01385 }
01386 }
01387
01388 void GCRoot::Set(const void * _object, size_t _size)
01389 {
01390 this->object = _object;
01391 this->size = _size;
01392 }
01393
01394 void GCRoot::Destroy()
01395 {
01396 Set(NULL, 0);
01397 if(gc) {
01398 gc->RemoveRoot(this);
01399 }
01400 gc = NULL;
01401 }
01402
01403 GCCallback::GCCallback(GC * _gc) : gc(_gc)
01404 {
01405 gc->AddCallback(this);
01406 }
01407
01408 GCCallback::~GCCallback()
01409 {
01410 if(gc) {
01411 gc->RemoveCallback(this);
01412 }
01413 }
01414
01415 void GCCallback::Destroy()
01416 {
01417 if(gc) {
01418 gc->RemoveCallback(this);
01419 }
01420 gc = NULL;
01421 }
01422
01423 #ifndef MMGC_THREADSAFE
01424 void GC::CheckThread()
01425 {
01426 #ifdef _DEBUG
01427 #ifdef WIN32
01428 GCAssertMsg(disableThreadCheck || m_gcThread == GetCurrentThreadId(), "Unsafe access to GC from wrong thread!");
01429 #endif
01430 #endif
01431 }
01432 #endif
01433
01434 bool GC::IsPointerToGCPage(const void *item)
01435 {
01436 USING_PAGE_MAP();
01437 if((uintptr)item >= memStart && (uintptr)item < memEnd)
01438 return GetPageMapValueAlreadyLocked((uintptr) item) != 0;
01439 return false;
01440 }
01441
01442 #ifdef MMGC_DRC
01443
01444 ZCT::ZCT()
01445 {
01446 zctSize = ZCT_START_SIZE;
01447 zctFreelist = NULL;
01448 reaping = false;
01449 gc = NULL;
01450 count = 0;
01451 zctReapThreshold = ZCT_REAP_THRESHOLD;
01452 }
01453
01454 ZCT::~ZCT()
01455 {
01456 gc->heapFree(zct, zctSize);
01457 }
01458
01459 void ZCT::SetGC(GC *gc)
01460 {
01461 this->gc = gc;
01462 zct = (RCObject**) gc->heapAlloc(zctSize);
01463 zctNext = zct;
01464 }
01465
01466 void ZCT::Add(RCObject *obj)
01467 {
01468 if(gc->collecting)
01469 {
01470
01471
01472 if(gc->dontAddToZCTDuringCollection)
01473 return;
01474
01475
01476 if(!GC::GetMark(obj))
01477 return;
01478 }
01479
01480 #if 0
01481
01482
01483 if(reaping && PLENTY_OF_STACK()) {
01484 {
01485 USING_CALLBACK_LIST(gc);
01486 GCCallback *cb = gc->m_callbacks;
01487 while(cb) {
01488 cb->prereap(obj);
01489 cb = cb->nextCB;
01490 }
01491 }
01492 if(gc->IsFinalized(obj))
01493 ((GCFinalizable*)obj)->~GCFinalizable();
01494 gc->Free(obj);
01495 return;
01496 }
01497 #endif
01498
01499 if(zctFreelist) {
01500 RCObject **nextFree = (RCObject**)*zctFreelist;
01501 *zctFreelist = obj;
01502 obj->setZCTIndex((int)(zctFreelist - zct));
01503 zctFreelist = nextFree;
01504 } else if(reaping && zctIndex > nextPinnedIndex) {
01505
01506 zctIndex--;
01507 GCAssert(zct[zctIndex] == NULL);
01508 obj->setZCTIndex(zctIndex);
01509 zct[zctIndex] = obj;
01510 } else if(zctNext - zct <= (RCObject::ZCT_INDEX>>8)) {
01511 *zctNext = obj;
01512 obj->setZCTIndex((int)(zctNext - zct));
01513 zctNext++;
01514 } else {
01515
01516 return;
01517 }
01518
01519 count++;
01520
01521 if(!reaping) {
01522
01523 if(obj->IsPinned())
01524 obj->Unpin();
01525 if(!gc->collecting && zctNext >= zct+zctReapThreshold)
01526 Reap();
01527 }
01528
01529 if(zctNext >= zct + zctSize*4096/sizeof(void *)) {
01530
01531 RCObject **newZCT = (RCObject**) gc->heap->Alloc(zctSize*2);
01532 memcpy(newZCT, zct, zctSize*GCHeap::kBlockSize);
01533 gc->heap->Free(zct);
01534 zctNext = newZCT + (zctNext-zct);
01535 zct = newZCT;
01536 zctSize *= 2;
01537 GCAssert(!zctFreelist);
01538 }
01539 }
01540
01541 void ZCT::Remove(RCObject *obj)
01542 {
01543 int index = obj->getZCTIndex();
01544 GCAssert(zct[index] == obj);
01545
01546 if(reaping)
01547 {
01548
01549
01550
01551
01552 zct[index] = NULL;
01553 }
01554 else
01555 {
01556 zct[index] = (RCObject*) zctFreelist;
01557 zctFreelist = &zct[index];
01558 }
01559 obj->ClearZCTFlag();
01560 count--;
01561 }
01562
01563 void ZCT::PinStackObjects(const void *start, size_t len)
01564 {
01565 RCObject **p = (RCObject**)start;
01566 RCObject **end = p + len/sizeof(RCObject*);
01567
01568 const void *_memStart = (const void*)gc->memStart;
01569 const void *_memEnd = (const void*)gc->memEnd;
01570
01571 while(p < end)
01572 {
01573 const void *val = GC::Pointer(*p++);
01574
01575 if(val < _memStart || val >= _memEnd)
01576 continue;
01577
01578 int bits = gc->GetPageMapValue((uintptr)val);
01579 bool doit = false;
01580 if (bits == GC::kGCAllocPage) {
01581 doit = GCAlloc::IsRCObject(val) && GCAlloc::FindBeginning(val) == GetRealPointer(val);
01582 } else if(bits == GC::kGCLargeAllocPageFirst) {
01583 doit = GCLargeAlloc::IsRCObject(val) && GCLargeAlloc::FindBeginning(val) == GetRealPointer(val);
01584 }
01585
01586 if(doit) {
01587 RCObject *obj = (RCObject*)val;
01588 obj->Pin();
01589 }
01590 }
01591 }
01592
01593 #if 0
01594
01595 void GC::CheckFreelists()
01596 {
01597 GCAlloc **allocs = containsPointersAllocs;
01598 for (int l=0; l < GC::kNumSizeClasses; l++) {
01599 GCAlloc *a = allocs[l];
01600 GCAlloc::GCBlock *_b = a->m_firstBlock;
01601 while(_b) {
01602 void *fitem = _b->firstFree;
01603 void *prev = 0;
01604 while(fitem) {
01605 if((uintptr(fitem) & 7) != 0) {
01606 _asm int 3;
01607 break;
01608 }
01609 if((uintptr(fitem) & ~0xfff) != uintptr(_b))
01610 _asm int 3;
01611 prev = fitem;
01612 fitem = *(void**)fitem;
01613 }
01614 _b = _b->next;
01615 }
01616 }
01617 }
01618 #endif
01619
01620 #ifdef _DEBUG
01621
01622 void GC::RCObjectZeroCheck(RCObject *item)
01623 {
01624 size_t size = Size(item)/sizeof(int);
01625 int *p = (int*)item;
01626
01627 p++;
01628 #ifdef MMGC_64BIT
01629 p++;
01630 size--;
01631 #endif
01632
01633
01634 if(incrementalValidation) {
01635 if(*p == (int32)0xcacacaca)
01636 return;
01637 }
01638 for(int i=1; i<(int)size; i++,p++)
01639 {
01640 if(*p)
01641 {
01642 #ifdef MEMORY_INFO
01643 PrintStackTrace(item);
01644 #endif
01645 GCAssertMsg(false, "RCObject didn't clean up itself.");
01646 }
01647 }
01648 }
01649
01650
01651 void CleanEntireStack()
01652 {
01653 #if defined(MMGC_IA32) && defined(WIN32)
01654
01655 register void *stackP;
01656 __asm {
01657 mov stackP,esp
01658 }
01659 MEMORY_BASIC_INFORMATION mib;
01660
01661 VirtualQuery(stackP, &mib, sizeof(MEMORY_BASIC_INFORMATION));
01662
01663 char *stackPeak = (char*) mib.BaseAddress;
01664 while(true)
01665 {
01666 VirtualQuery(stackPeak - 4096, &mib, sizeof(MEMORY_BASIC_INFORMATION));
01667
01668
01669
01670 if((mib.Protect & PAGE_GUARD) == PAGE_GUARD || mib.State != MEM_COMMIT)
01671 break;
01672 stackPeak -= 4096;
01673 }
01674 size_t amount = (char*) stackP - stackPeak - 128;
01675 {
01676 void *stack = alloca(amount);
01677 if(stack) {
01678 memset(stack, 0, amount);
01679 }
01680 }
01681 #endif // _MMGC_IA32
01682 }
01683 #endif // _DEBUG
01684
01685 void ZCT::Reap()
01686 {
01687 if(gc->collecting || reaping || count == 0)
01688 return;
01689
01690 uint64 start = 0;
01691 if(gc->gcstats) {
01692 start = GC::GetPerformanceCounter();
01693 }
01694 uint32 pagesStart = (uint32)gc->totalGCPages;
01695 uint32 numObjects=0;
01696 uint32 objSize=0;
01697
01698 reaping = true;
01699
01700 SAMPLE_FRAME("[reap]", gc->core());
01701
01702
01703 GCWorkItem item;
01704 MMGC_GET_STACK_EXTENTS(gc, item.ptr, item._size);
01705 PinStackObjects(item.ptr, item._size);
01706
01707
01708
01709
01710
01711 zctIndex = 0;
01712 nextPinnedIndex = 0;
01713
01714
01715 {
01716 USING_CALLBACK_LIST(gc);
01717 GCCallback *cb = gc->m_callbacks;
01718 while(cb) {
01719 cb->prereap();
01720 cb = cb->nextCB;
01721 }
01722 }
01723
01724 #ifdef _DEBUG
01725 if(gc->validateDefRef) {
01726
01727 gc->marking = false;
01728 gc->m_incrementalWork.Keep(0);
01729
01730 CleanEntireStack();
01731 gc->Trace(item.ptr, item._size);
01732 }
01733 #endif
01734
01735
01736
01737
01738 while(zctFreelist) {
01739 RCObject **next = (RCObject**)*zctFreelist;
01740 *zctFreelist = 0;
01741 zctFreelist = next;
01742 }
01743
01744 while(zct+zctIndex < zctNext) {
01745 SAMPLE_CHECK();
01746 RCObject *rcobj = zct[zctIndex++];
01747 if(rcobj && !rcobj->IsPinned()) {
01748 rcobj->ClearZCTFlag();
01749 zct[zctIndex-1] = NULL;
01750 count--;
01751 #ifdef _DEBUG
01752 if(gc->validateDefRef) {
01753 if(gc->GetMark(rcobj)) {
01754 #ifdef MEMORY_INFO
01755 rcobj->DumpHistory();
01756 GCDebugMsg(false, "Back pointer chain:");
01757 gc->DumpBackPointerChain(rcobj);
01758 #endif
01759 GCAssertMsg(false, "Zero count object reachable, ref counts not correct!");
01760 }
01761 }
01762 #endif
01763
01764 {
01765 USING_CALLBACK_LIST(gc);
01766 GCCallback *cbb = gc->m_callbacks;
01767 while(cbb) {
01768 cbb->prereap(rcobj);
01769 cbb = cbb->nextCB;
01770 }
01771 }
01772
01773 GCAssert(*(int*)rcobj != 0);
01774 GCAssert(gc->IsFinalized(rcobj));
01775
01776 ((GCFinalizable*)rcobj)->Finalize();
01777 numObjects++;
01778 objSize += (uint32)GC::Size(rcobj);
01779 gc->Free(rcobj);
01780
01781 GCAssert(gc->weakRefs.get(rcobj) == NULL);
01782 } else if(rcobj) {
01783
01784 rcobj->Unpin();
01785 if(nextPinnedIndex != zctIndex-1) {
01786 rcobj->setZCTIndex(nextPinnedIndex);
01787 GCAssert(zct[nextPinnedIndex] == NULL);
01788 zct[nextPinnedIndex] = rcobj;
01789 zct[zctIndex-1] = NULL;
01790 }
01791 nextPinnedIndex++;
01792 }
01793 }
01794
01795 zctNext = zct + nextPinnedIndex;
01796 zctReapThreshold = count + ZCT_REAP_THRESHOLD;
01797 if(zctReapThreshold > int(zctSize*GCHeap::kBlockSize/sizeof(RCObject*)))
01798 zctReapThreshold = zctSize*GCHeap::kBlockSize/sizeof(RCObject*);
01799 GCAssert(nextPinnedIndex == count);
01800 zctIndex = nextPinnedIndex = 0;
01801
01802
01803 {
01804 USING_CALLBACK_LIST(gc);
01805 GCCallback *cb = gc->m_callbacks;
01806 while(cb) {
01807 cb->postreap();
01808 cb = cb->nextCB;
01809 }
01810 }
01811 if(gc->gcstats && numObjects) {
01812 gc->gclog("[mem] DRC reaped %d objects (%d kb) freeing %d pages (%d kb) in %.2f millis (%.4f s)\n",
01813 numObjects, objSize>>10, pagesStart - gc->totalGCPages, gc->totalGCPages*GCHeap::kBlockSize >> 10,
01814 GC::duration(start), gc->duration(gc->t0)/1000);
01815 }
01816 reaping = false;
01817
01818 #ifdef _DEBUG
01819 if(gc->validateDefRef) {
01820 gc->Sweep();
01821 }
01822 #endif
01823 }
01824
01825 #ifdef SOLARIS
01826
01827 #ifdef MMGC_SPARC
01828 #define FLUSHWIN() asm("ta 3");
01829 #else
01830 #define FLUSHWIN()
01831 #endif
01832 #define MAX_FRAMES 500
01833
01834 static int validaddr(void * addr)
01835 {
01836 static long pagemask = -1;
01837 char c;
01838 if (pagemask == -1) {
01839 pagemask = ~(sysconf(_SC_PAGESIZE) - 1);
01840 }
01841 addr = (void *)((long)addr & pagemask);
01842 if (mincore((char *)addr, 1, &c) == -1 && errno == ENOMEM) {
01843 return 0;
01844 } else {
01845 return 1;
01846 }
01847 }
01848
01849 pthread_key_t stackTopKey = NULL;
01850
01851 uintptr GC::GetStackTop() const
01852 {
01853 if(stackTopKey == NULL)
01854 {
01855 int res = pthread_key_create(&stackTopKey, NULL);
01856 GCAssert(res == 0);
01857 }
01858
01859 void *stackTop = pthread_getspecific(stackTopKey);
01860 if(stackTop)
01861 return (uintptr)stackTop;
01862
01863 struct frame *sp;
01864 int i;
01865 int *iptr;
01866
01867 stack_t st;
01868 stack_getbounds(&st);
01869 uintptr_t stack_base = (uintptr_t)st.ss_sp + st.ss_size;
01870
01871 FLUSHWIN();
01872
01873 sp = (struct frame *)_getfp();
01874 stackTop = (void *)sp;
01875 for (i = 0; i < MAX_FRAMES && sp && (uintptr_t)sp < stack_base; i++) {
01876 if (!validaddr( sp ) || !validaddr(&sp->fr_savpc) || !sp->fr_savpc ) {
01877 break;
01878 }
01879 stackTop = (void *)sp;
01880 sp = ( struct frame * )sp->fr_savfp;
01881 }
01882 pthread_setspecific(stackTopKey, stackTop);
01883 return (uintptr)stackTop;
01884 }
01885 #elif defined(AVMPLUS_UNIX) // SOLARIS
01886 pthread_key_t stackTopKey = 0;
01887
01888 uintptr GC::GetStackTop() const
01889 {
01890 if(stackTopKey == 0)
01891 {
01892 #ifdef DEBUG
01893 int res =
01894 #endif
01895 pthread_key_create(&stackTopKey, NULL);
01896 GCAssert(res == 0);
01897 }
01898
01899 void *stackTop = pthread_getspecific(stackTopKey);
01900 if(stackTop)
01901 return (uintptr)stackTop;
01902
01903 size_t sz;
01904 void *s_base;
01905 pthread_attr_t attr;
01906
01907 pthread_attr_init(&attr);
01908
01909 #ifdef HAVE_PTHREAD_NP_H
01910 int res = pthread_attr_get_np(pthread_self(),&attr);
01911 #else // HAVE_PTHREAD_NP_H
01912 int res = pthread_getattr_np(pthread_self(),&attr);
01913 #endif // HAVE_PTHREAD_NP_H
01914 GCAssert(res == 0);
01915
01916 if(res)
01917 {
01918
01919 return 0;
01920 }
01921
01922 res = pthread_attr_getstack(&attr,&s_base,&sz);
01923 GCAssert(res == 0);
01924 pthread_attr_destroy(&attr);
01925
01926 stackTop = (void*) ((size_t)s_base + sz);
01927
01928 GCAssert(stackTop > &sz);
01929 pthread_setspecific(stackTopKey, stackTop);
01930 return (uintptr)stackTop;
01931
01932 }
01933 #endif // AVMPLUS_UNIX
01934
01935 void GC::gclog(const char *format, ...)
01936 {
01937 static bool ingclog=false;
01938
01939 (void)format;
01940 char buf[4096];
01941 va_list argptr;
01942
01943 va_start(argptr, format);
01944 vsprintf(buf, format, argptr);
01945 va_end(argptr);
01946
01947 GCAssert(strlen(buf) < 4096);
01948
01949 {
01950 USING_CALLBACK_LIST(this);
01951 GCCallback *cb = m_callbacks;
01952 if(cb) {
01953 cb->log(buf);
01954 cb = cb->nextCB;
01955 }
01956 }
01957
01958 if(!ingclog) {
01959 ingclog = true;
01960 updateGrossMemoryStats();
01961 ingclog = false;
01962 }
01963 }
01964
01965 #ifdef MEMORY_INFO
01966 void GC::DumpBackPointerChain(void *o, pDumpBackCallbackProc proc, void *context)
01967 {
01968 int *p = (int*)GetRealPointer ( o ) ;
01969 int size = *p++;
01970 int traceIndex = *p++;
01971
01972
01973
01974
01975 const char *typeName = GetTypeName(traceIndex, o);
01976
01977 #if (defined(WIN32) && !defined(UNDER_CE) && !defined(MMGC_64BIT)) || ( defined(AVMPLIS_UNIX) && !defined(__ICC) )
01978 if (strncmp(typeName, "unknown ", 7))
01979 {
01980 try {
01981 const std::type_info *ti = &typeid(*(MMgc::GCObject*)p);
01982 if (ti->name() && (int(ti->name()) > 0x10000))
01983 typeName = ti->name();
01984
01985 char c = *typeName;
01986 (void)c;
01987 } catch(...) {
01988 typeName = "unknown";
01989 }
01990 }
01991 #endif
01992
01993
01994 if (!strncmp(typeName, "class ", 6))
01995 typeName += 6;
01996 GCDebugMsg(false, "Object: (%s *)0x%x\n", typeName, p);
01997 if (proc)
01998 proc(context, o, typeName);
01999 PrintStackTraceByIndex(traceIndex);
02000 GCDebugMsg(false, "---\n");
02001
02002 p += 1 + (size>>2);
02003 void *container = (void*)(*(void**)p);
02004 if(container && IsPointerToGCPage(container))
02005 DumpBackPointerChain(container, proc, context);
02006 else
02007 {
02008 GCDebugMsg(false, "GCRoot object: 0x%x\n", container);
02009 if((uintptr)container >= memStart && (uintptr)container < memEnd)
02010 PrintStackTrace(container);
02011 }
02012 }
02013
02014 void GC::WriteBackPointer(const void *item, const void *container, size_t itemSize)
02015 {
02016 GCAssert(container != NULL);
02017 uint32 *p = (uint32*) item;
02018 uint32 size = *p++;
02019 if(size && size <= itemSize) {
02020
02021 p += (2 + (size>>2));
02022 GCAssert(sizeof(uintptr) == sizeof(void*));
02023 *(uintptr*)p = (uintptr) container;
02024 }
02025 }
02026
02027 #endif
02028
02029 bool GC::IsRCObject(const void *item)
02030 {
02031 int bits;
02032 {
02033 USING_PAGE_MAP();
02034
02035 if ((uintptr)item < memStart || (uintptr)item >= memEnd || ((uintptr)item&0xfff) == 0)
02036 return false;
02037 bits = GetPageMapValueAlreadyLocked((uintptr)item);
02038 }
02039
02040 item = GetRealPointer(item);
02041 switch(bits)
02042 {
02043 case kGCAllocPage:
02044 if((char*)item < ((GCAlloc::GCBlock*)((uintptr)item&~0xfff))->items)
02045 return false;
02046 return GCAlloc::IsRCObject(item);
02047 case kGCLargeAllocPageFirst:
02048 return GCLargeAlloc::IsRCObject(item);
02049 default:
02050 return false;
02051 }
02052 }
02053
02054 #endif // MMGC_DRC
02055
02056 #ifdef MEMORY_INFO
02057
02058 int DumpAlloc(GCAlloc *a)
02059 {
02060 int inUse = a->GetNumAlloc() * a->GetItemSize();
02061 int maxAlloc = a->GetMaxAlloc()* a->GetItemSize();
02062 int efficiency = maxAlloc > 0 ? inUse * 100 / maxAlloc : 100;
02063 if(inUse) {
02064 GCDebugMsg(false, "Allocator(%d): %d%% efficiency %d kb out of %d kb\n", a->GetItemSize(), efficiency, inUse>>10, maxAlloc>>10);
02065 }
02066 return maxAlloc-inUse;
02067 }
02068
02069 void GC::DumpMemoryInfo()
02070 {
02071 if(heap->enableMemoryProfiling)
02072 {
02073 DumpFatties();
02074 if (dumpSizeClassState)
02075 {
02076 int waste=0;
02077 for(int i=0; i < kNumSizeClasses; i++)
02078 {
02079 waste += DumpAlloc(containsPointersAllocs[i]);
02080 #ifdef MMGC_DRC
02081 waste += DumpAlloc(containsPointersRCAllocs[i]);
02082 #endif
02083 waste += DumpAlloc(noPointersAllocs[i]);
02084 }
02085 GCDebugMsg(false, "Wasted %d kb\n", waste>>10);
02086
02087 }
02088 }
02089 }
02090
02091 #endif
02092
02093 #ifdef _DEBUG
02094
02095 void GC::CheckFreelist(GCAlloc *gca)
02096 {
02097 GCAlloc::GCBlock *b = gca->m_firstFree;
02098 while(b)
02099 {
02100 void *freelist = b->firstFree;
02101 while(freelist)
02102 {
02103
02104
02105 GCAssert(freelist == 0 || ((uintptr) freelist >= (uintptr) b->items && (uintptr) freelist < (uintptr) b + GCHeap::kBlockSize));
02106 freelist = *((void**)freelist);
02107 }
02108 b = b->nextFree;
02109 }
02110 }
02111
02112 void GC::CheckFreelists()
02113 {
02114 for(int i=0; i < kNumSizeClasses; i++)
02115 {
02116 CheckFreelist(containsPointersAllocs[i]);
02117 CheckFreelist(noPointersAllocs[i]);
02118 }
02119 }
02120
02121 void GC::UnmarkedScan(const void *mem, size_t size)
02122 {
02123 uintptr lowerBound = memStart;
02124 uintptr upperBound = memEnd;
02125
02126 uintptr *p = (uintptr *) mem;
02127 uintptr *end = p + (size / sizeof(void*));
02128
02129 while(p < end)
02130 {
02131 uintptr val = *p++;
02132
02133 if(val < lowerBound || val >= upperBound)
02134 continue;
02135
02136
02137 int bits = GetPageMapValueAlreadyLocked(val);
02138 switch(bits)
02139 {
02140 case 0:
02141 continue;
02142 break;
02143 case kGCAllocPage:
02144 GCAssert(GCAlloc::ConservativeGetMark((const void*) (val&~7), true));
02145 break;
02146 case kGCLargeAllocPageFirst:
02147 GCAssert(GCLargeAlloc::ConservativeGetMark((const void*) (val&~7), true));
02148 break;
02149 default:
02150 GCAssertMsg(false, "Invalid pageMap value");
02151 break;
02152 }
02153 }
02154 }
02155
02156 void GC::FindUnmarkedPointers()
02157 {
02158 MMGC_ASSERT_EXCLUSIVE_GC(this);
02159
02160 if(findUnmarkedPointers)
02161 {
02162 uintptr m = memStart;
02163
02164 while(m < memEnd)
02165 {
02166
02167 int bits = GetPageMapValue(m);
02168 if(bits == kNonGC) {
02169 UnmarkedScan((const void*)m, GCHeap::kBlockSize);
02170 m += GCHeap::kBlockSize;
02171 } else if(bits == kGCLargeAllocPageFirst) {
02172 GCLargeAlloc::LargeBlock *lb = (GCLargeAlloc::LargeBlock*)m;
02173 const void *item = GetUserPointer((const void*)(lb+1));
02174 if(GCLargeAlloc::GetMark(item) && GCLargeAlloc::ContainsPointers(GetRealPointer(item))) {
02175 UnmarkedScan(item, GC::Size(item));
02176 }
02177 m += lb->GetNumBlocks() * GCHeap::kBlockSize;
02178 } else if(bits == kGCAllocPage) {
02179
02180 GCAlloc::GCBlock *b = (GCAlloc::GCBlock *) m;
02181 for (int i=0; i < b->alloc->m_itemsPerBlock; i++) {
02182
02183 int marked = GCAlloc::GetBit(b, i, GCAlloc::kMark);
02184 if (!marked) {
02185 void* item = (char*)b->items + b->alloc->m_itemSize*i;
02186 if(GCAlloc::ContainsPointers(item)) {
02187 UnmarkedScan(GetUserPointer(item), b->alloc->m_itemSize - DebugSize());
02188 }
02189 }
02190 }
02191
02192 m += GCHeap::kBlockSize;
02193 }
02194 }
02195 }
02196 }
02197
02198
02199 #define ALLOCA_AND_FILL_WITH_SPACES(b, i) \
02200 { b = (char*)alloca((3*(i))+1); \
02201 int n = 0; \
02202 for(; n<3*(i); n++) b[n] = ' '; \
02203 b[n] = '\0'; }
02204
02205 void GC::ProbeForMatch(const void *mem, size_t size, uintptr value, int recurseDepth, int currentDepth)
02206 {
02207 uintptr lowerBound = memStart;
02208 uintptr upperBound = memEnd;
02209
02210 uintptr *p = (uintptr *) mem;
02211 uintptr *end = p + (size / sizeof(void*));
02212
02213 int bits = GetPageMapValue((uintptr)mem);
02214
02215 while(p < end)
02216 {
02217 uintptr val = *p++;
02218
02219 if(val < lowerBound || val >= upperBound)
02220 continue;
02221
02222
02223 if (val == value)
02224 {
02225
02226 uintptr* where = p-1;
02227 GCHeap::HeapBlock* block = heap->AddrToBlock(where);
02228
02229 GCAssertMsg(block->committed, "Means we are probing uncommitted memory. not good");
02230 int* ptr;
02231
02232 switch(bits)
02233 {
02234 case kNonGC:
02235 {
02236 if (block->size == 1)
02237 {
02238
02239 FixedAlloc::FixedBlock* fixed = (FixedAlloc::FixedBlock*) block->baseAddr;
02240 int fixedsize = fixed->size;
02241
02242
02243 uintptr startAt = (uintptr) &(fixed->items[0]);
02244 uintptr item = ((uintptr)where-startAt) / fixedsize;
02245
02246 ptr = (int*) ( startAt + (item*fixedsize) );
02247 }
02248 else
02249 {
02250
02251 ptr = (int*) block->baseAddr;
02252 }
02253 }
02254 break;
02255
02256 default:
02257 ptr = ((int*)FindBeginning(where)) - 2;
02258 break;
02259 }
02260
02261 int taggedSize = *ptr;
02262 int traceIndex = *(ptr+1);
02263 int* real = (ptr+2);
02264
02265 char* buffer = 0;
02266 ALLOCA_AND_FILL_WITH_SPACES(buffer, currentDepth);
02267
02268 if (buffer) GCDebugMsg(false, buffer);
02269 GCDebugMsg(false, "Location: 0x%08x Object: 0x%08x (size %d)\n", where, real, taggedSize);
02270 if (buffer) GCDebugMsg(false, buffer);
02271 #ifdef MEMORY_INFO
02272 PrintStackTraceByIndex(traceIndex);
02273 #else
02274 (void)traceIndex;
02275 #endif
02276
02277 if (recurseDepth > 0)
02278 WhosPointingAtMe(real, recurseDepth-1, currentDepth+1);
02279 }
02280 }
02281 }
02282
02291 void GC::WhosPointingAtMe(void* me, int recurseDepth, int currentDepth)
02292 {
02293 #ifdef MMGC_THREADSAFE
02294 if (currentDepth == 0)
02295 pageMapLock.Acquire();
02296 #endif
02297
02298 uintptr val = (uintptr)me;
02299 uintptr m = memStart;
02300
02301 char* buffer = 0;
02302 ALLOCA_AND_FILL_WITH_SPACES(buffer, currentDepth);
02303
02304 if (buffer) GCDebugMsg(false, buffer);
02305 GCDebugMsg(false, "[%d] Probing for pointers to : 0x%08x\n", currentDepth, me);
02306 while(m < memEnd)
02307 {
02308 #ifdef WIN32
02309
02310 MEMORY_BASIC_INFORMATION mib;
02311 VirtualQuery((void*) m, &mib, sizeof(MEMORY_BASIC_INFORMATION));
02312 if((mib.Protect & PAGE_READWRITE) == 0)
02313 {
02314 m += mib.RegionSize;
02315 continue;
02316 }
02317 #endif
02318
02319
02320 int bits = GetPageMapValueAlreadyLocked(m);
02321 if(bits == kNonGC)
02322 {
02323 ProbeForMatch((const void*)m, GCHeap::kBlockSize, val, recurseDepth, currentDepth);
02324 m += GCHeap::kBlockSize;
02325 }
02326 else if(bits == kGCLargeAllocPageFirst)
02327 {
02328 GCLargeAlloc::LargeBlock *lb = (GCLargeAlloc::LargeBlock*)m;
02329 const void *item = GetUserPointer((const void*)(lb+1));
02330 bool marked = GCLargeAlloc::GetMark(item);
02331 if (marked)
02332 {
02333 if(GCLargeAlloc::ContainsPointers(GetRealPointer(item)))
02334 {
02335 ProbeForMatch(item, GC::Size(item), val, recurseDepth, currentDepth);
02336 }
02337 }
02338 m += lb->GetNumBlocks() * GCHeap::kBlockSize;
02339 }
02340 else if(bits == kGCAllocPage)
02341 {
02342
02343 GCAlloc::GCBlock *b = (GCAlloc::GCBlock *) m;
02344 for (int i=0; i < b->alloc->m_itemsPerBlock; i++)
02345 {
02346 int marked = GCAlloc::GetBit(b, i, GCAlloc::kMark);
02347 if (marked)
02348 {
02349 void* item = (char*)b->items + b->alloc->m_itemSize*i;
02350 if(GCAlloc::ContainsPointers(item))
02351 {
02352 ProbeForMatch(GetUserPointer(item), b->alloc->m_itemSize - DebugSize(), val, recurseDepth, currentDepth);
02353 }
02354 }
02355 }
02356 m += GCHeap::kBlockSize;
02357 }
02358 else
02359 {
02360 GCAssertMsg(false, "Oh seems we missed a case...Tom any ideas here?");
02361
02362 }
02363 }
02364
02365 #ifdef MMGC_THREADSAFE
02366 if (currentDepth == 0)
02367 pageMapLock.Release();
02368 #endif
02369 }
02370 #undef ALLOCA_AND_FILL_WITH_SPACES
02371 #endif
02372
02373
02374 void GC::StartIncrementalMark()
02375 {
02376 GCAssert(!marking);
02377 GCAssert(!collecting);
02378
02379 lastStartMarkIncrementCount = markIncrements;
02380
02381
02382 stackCleaned = false;
02383
02384 marking = true;
02385
02386 GCAssert(m_incrementalWork.Count() == 0);
02387
02388 uint64 start = GetPerformanceCounter();
02389
02390
02391 for(int i=0; i < kNumSizeClasses; i++) {
02392 #ifdef MMGC_DRC
02393 containsPointersRCAllocs[i]->SweepNeedsSweeping();
02394 #endif
02395 containsPointersAllocs[i]->SweepNeedsSweeping();
02396 noPointersAllocs[i]->SweepNeedsSweeping();
02397 }
02398
02399
02400 #ifdef _DEBUG
02401 for(int i=0; i < kNumSizeClasses; i++) {
02402 #ifdef MMGC_DRC
02403 containsPointersRCAllocs[i]->CheckMarks();
02404 #endif
02405 containsPointersAllocs[i]->CheckMarks();
02406 noPointersAllocs[i]->CheckMarks();
02407 }
02408 #endif
02409
02410 {
02411 #ifdef GCHEAP_LOCK
02412 GCAcquireSpinlock lock(m_rootListLock);
02413 #endif
02414 GCRoot *r = m_roots;
02415 while(r) {
02416 GCWorkItem item = r->GetWorkItem();
02417 if(item.ptr)
02418 MarkItem(item, m_incrementalWork);
02419 r = r->next;
02420 }
02421 }
02422 markTicks += GetPerformanceCounter() - start;
02423 IncrementalMark();
02424 }
02425
02426 #if 0
02427
02428 void GC::MarkItem_MMX(const void *ptr, size_t size, GCStack<GCWorkItem> &work)
02429 {
02430 uintptr *p = (uintptr*) ptr;
02431
02432 if(!p)
02433 return;
02434
02435 bytesMarked += size;
02436 marks++;
02437
02438 uintptr *end = p + (size / sizeof(void*));
02439 uintptr thisPage = (uintptr)p & ~0xfff;
02440
02441
02442 if(IsPointerToGCPage(ptr))
02443 {
02444 int b = SetMark(ptr);
02445 #if defined(_DEBUG) && !defined(DEBUGGER) // sampler does some marking which triggers this
02446
02447
02448
02449 if(!validateDefRef) {
02450 GCAssert(!b);
02451 }
02452 #endif
02453 }
02454
02455
02456 _asm {
02457
02458 movq mm0,memStart
02459 }
02460
02461 while(p < end)
02462 {
02463 _asm {
02464 mov ebx, [p]
02465 mov ecx, [count]
02466 sar ecx, 1
02467 mov eax, dword ptr [lowerBound]
02468 dec eax
02469 movd mm1, eax
02470 movd mm2, dword ptr [upperBound]
02471 punpckldq mm1, mm1
02472 punpckldq mm2, mm2
02473 mov eax, 3
02474 movd mm5, eax
02475 punpckldq mm5, mm5
02476 MarkLoop:
02477 movq mm0, qword ptr [ebx]
02478 movq mm3, mm0
02479 pcmpgtd mm3, mm1
02480 movq mm4, mm2
02481 pcmpgtd mm4, mm0
02482 pand mm3, mm4
02483 packssdw mm3, mm3
02484 movd eax, mm3
02485 or eax, eax
02486 jz Advance
02487
02488
02489 psubd mm0, mm1
02490 psrld mm0, 12
02491
02492
02493 movq mm6, mm0
02494 pand mm6, mm5
02495 pslld mm6, 1
02496 packssdw mm6, mm6
02497
02498
02499 psrld mm0, 2
02500 packssdw mm0, mm0
02501
02502
02503 push ecx
02504
02505
02506
02507 push [workAddr]
02508 movd edx, mm6
02509 push edx
02510 movd edx, mm0
02511 push edx
02512 push eax
02513 push dword ptr [ebx+4]
02514 push dword ptr [ebx]
02515 mov ecx, [this]
02516 call ConservativeMarkMMXHelper
02517
02518 pop ecx
02519
02520 Advance:
02521 add ebx, 8
02522 loop MarkLoop
02523 mov dword ptr [p], ebx
02524 }
02525 }
02526 }
02527
02528 #endif
02529
02530 #ifdef MMGC_INTERIOR_PTRS
02531 inline bool IsLargeAllocPage(int bits) {
02532 return (bits == GC::kGCLargeAllocPageFirst
02533 || bits == GC::kGCLargeAllocPageRest);
02534 }
02535 #else
02536 inline bool IsLargeAllocPage(int bits) {
02537 return bits == GC::kGCLargeAllocPageFirst;
02538 }
02539 #endif
02540
02541 #ifdef WERNER_MODE
02542 #define RECURSIVE_MARK
02543
02544 class MarkList
02545 {
02546 public:
02547 static MarkList *current;
02548 static int offset;
02549 MarkList(GCWorkItem &item) : prev(current), wi(item), off(offset)
02550 {
02551 current = this;
02552 }
02553 ~MarkList() { current = prev; }
02554 MarkList *prev;
02555 GCWorkItem &wi;
02556 int off;
02557 };
02558 MarkList *MarkList::current = NULL;
02559 int MarkList::offset = -1;
02560 #endif
02561
02562 void GC::MarkItem(GCWorkItem &wi, GCStack<GCWorkItem> &work)
02563 {
02564 size_t size = wi.GetSize();
02565 uintptr *p = (uintptr*) wi.ptr;
02566
02567 #ifdef WERNER_MODE
02568 MarkList me(wi);
02569
02570 if(p == shouldGo) {
02571 MarkList *wl = MarkList::current;
02572 while(wl) {
02573 const char *name = "";
02574
02575 #if 0
02576 static bool tryit = true;
02577 if (tryit)
02578 {
02579 try {
02580 const std::type_info *ti = &typeid(*(MMgc::GCFinalizedObject*)wl->wi.ptr);
02581 if (ti->name() && (int(ti->name()) > 0x10000))
02582 name = ti->name();
02583 } catch(...) {
02584 name = "unknown";
02585 }
02586 }
02587 #endif
02588
02589 if(wl->prev)
02590 sprintf(statusBuffer, "0x%x+%d -> 0x%x size=%d (%s)\n", (unsigned int)wl->prev->wi.ptr, wl->off, (unsigned int)wl->wi.ptr, wl->wi.GetSize(), name);
02591 else
02592 sprintf(statusBuffer, "0x%x : %d (%s)\n", (unsigned int)wl->wi.ptr, wl->wi.GetSize(), name);
02593 wl = wl->prev;
02594 OutputDebugString(statusBuffer);
02595 }
02596 sprintf(statusBuffer, "\n");
02597 OutputDebugString(statusBuffer);
02598
02599 }
02600 #endif
02601 bytesMarked += size;
02602 marks++;
02603
02604 uintptr *end = p + (size / sizeof(void*));
02605 uintptr thisPage = (uintptr)p & ~0xfff;
02606
02607
02608 if(wi.IsGCItem())
02609 {
02610 int b = SetMark(wi.ptr);
02611 (void)b;
02612 #ifdef _DEBUG
02613
02614
02615
02616 if(!validateDefRef) {
02617 GCAssert(!b);
02618 }
02619 #endif
02620 }
02621 else
02622 {
02623 GCAssert(!IsPointerToGCPage(wi.ptr));
02624 }
02625
02626 uintptr _memStart = memStart;
02627 uintptr _memEnd = memEnd;
02628
02629 #ifdef DEBUGGER
02630 numObjects++;
02631 objSize+=(uint32)size;
02632 #endif
02633
02634 while(p < end)
02635 {
02636 #ifdef WERNER_MODE
02637 MarkList::offset = (int)p - (int)wi.ptr;
02638 #endif
02639
02640 uintptr val = *p++;
02641
02642 if(val < _memStart || val >= _memEnd)
02643 continue;
02644
02645
02646 int bits = GetPageMapValue(val);
02647
02648 if (bits == kGCAllocPage)
02649 {
02650 const void *item;
02651 GCAlloc::GCBlock *block = (GCAlloc::GCBlock*) (val & ~0xFFF);
02652
02653 #ifdef MMGC_INTERIOR_PTRS
02654 item = (void*) val;
02655 #else
02656
02657 item = GetRealPointer((const void*) (val & ~7));
02658 #endif
02659
02660
02661 if(item < block->items)
02662 continue;
02663
02664 int itemNum = GCAlloc::GetIndex(block, item);
02665 #ifdef MMGC_INTERIOR_PTRS
02666
02667 item = block->items + itemNum * block->size;
02668 #else
02669
02670
02671 if (block->items + itemNum * block->size != item)
02672 {
02673 #ifdef MMGC_64BIT
02674
02675
02676 if ((block->items + itemNum * block->size + sizeof(void *)) == item)
02677 item = block->items + itemNum * block->size;
02678 else
02679 #endif // MMGC_64BIT
02680 continue;
02681 }
02682 #endif
02683
02684
02685
02686 uint32 *pbits = &block->GetBits()[itemNum>>3];
02687 int shift = (itemNum&0x7)<<2;
02688 int bits2 = *pbits;
02689
02690 if((bits2 & ((GCAlloc::kMark|GCAlloc::kQueued)<<shift)) == 0)
02691 {
02692 if(block->alloc->ContainsPointers())
02693 {
02694 const void *realItem = item;
02695 uint32 itemSize = block->size;
02696 #ifdef MEMORY_INFO
02697 realItem = GetUserPointer(realItem);
02698 itemSize -= (uint32)DebugSize();
02699 #endif
02700 if(((uintptr)realItem & ~0xfff) != thisPage)
02701 {
02702 *pbits = bits2 | (GCAlloc::kQueued << shift);
02703 block->gc->PushWorkItem(work, GCWorkItem(realItem, itemSize, true));
02704 }
02705 else
02706 {
02707
02708 *pbits = bits2 & ~(GCAlloc::kQueued << shift);
02709
02710
02711
02712 GCWorkItem newItem(realItem, itemSize, true);
02713 MarkItem(newItem, work);
02714 }
02715 }
02716 else
02717 {
02718
02719 *pbits = bits2 | (GCAlloc::kMark << shift);
02720 }
02721 #if defined(MEMORY_INFO)
02722 GC::WriteBackPointer(item, (end==(void*)0x130000) ? p-1 : wi.ptr, block->size);
02723 #endif
02724 }
02725 }
02726 else if (IsLargeAllocPage(bits))
02727 {
02728
02729 const void* item;
02730
02731 #ifdef MMGC_INTERIOR_PTRS
02732 if (bits == kGCLargeAllocPageFirst)
02733 {
02734
02735 if ((val & 0xffff) < sizeof(GCLargeAlloc::LargeBlock))
02736 continue;
02737
02738 item = (void *) ((val & ~0xfff) |
02739 sizeof(GCLargeAlloc::LargeBlock));
02740 }
02741 else
02742 {
02743 item = GetRealPointer(FindBeginning((void *) val));
02744 }
02745 #else
02746
02747 item = GetRealPointer((const void*) (val & ~7));
02748
02749
02750
02751 if(((uintptr) item & 0xfff) != sizeof(GCLargeAlloc::LargeBlock))
02752 continue;
02753 #endif
02754
02755 GCLargeAlloc::LargeBlock *b = GCLargeAlloc::GetBlockHeader(item);
02756 if((b->flags & (GCLargeAlloc::kQueuedFlag|GCLargeAlloc::kMarkFlag)) == 0)
02757 {
02758 uint32 usize = b->usableSize;
02759 if((b->flags & GCLargeAlloc::kContainsPointers) != 0)
02760 {
02761 b->flags |= GCLargeAlloc::kQueuedFlag;
02762 const void *realItem = item;
02763 #ifdef MEMORY_INFO
02764 realItem = GetUserPointer(item);
02765 usize -= (uint32)DebugSize();
02766 #endif
02767 b->gc->PushWorkItem(work, GCWorkItem(realItem, usize, true));
02768 }
02769 else
02770 {
02771
02772 b->flags |= GCLargeAlloc::kMarkFlag;
02773 }
02774 #if defined(MEMORY_INFO)
02775 GC::WriteBackPointer(item, end==(void*)0x130000 ? p-1 : wi.ptr, usize);
02776 #endif
02777 }
02778 }
02779 }
02780 }
02781
02782 uint64 GC::GetPerformanceCounter()
02783 {
02784 #if defined(MMGC_PORTING_API)
02785 return MMGC_PortAPI_Time();
02786 #else
02787 #ifdef WIN32
02788 LARGE_INTEGER value;
02789 QueryPerformanceCounter(&value);
02790 return value.QuadPart;
02791 #elif defined SOLARIS
02792 uint64 retval = gethrtime();
02793 return retval;
02794 #elif defined(_MAC)
02795 return mach_absolute_time();
02796 #elif defined(AVMPLUS_UNIX)
02797 struct timeval tv;
02798 ::gettimeofday(&tv, NULL);
02799
02800 uint64 seconds = (uint64)(tv.tv_sec * 1000000);
02801 uint64 microseconds = (uint64)tv.tv_usec;
02802 uint64 result = seconds + microseconds;
02803
02804 return result;
02805 #else
02806 #error "Need high res timer"
02807 #endif
02808 #endif
02809 }
02810
02811 uint64 GC::GetPerformanceFrequency()
02812 {
02813 #if defined(MMGC_PORTING_API)
02814 return MMGC_PortAPI_Frequency();
02815 #else
02816 #ifdef WIN32
02817 static uint64 gPerformanceFrequency = 0;
02818 if (gPerformanceFrequency == 0) {
02819 QueryPerformanceFrequency((LARGE_INTEGER*)&gPerformanceFrequency);
02820 }
02821 return gPerformanceFrequency;
02822 #elif defined(_MAC)
02823 static mach_timebase_info_data_t info;
02824 static uint64 frequency = 0;
02825 if ( frequency == 0 ) {
02826 (void) mach_timebase_info(&info);
02827 frequency = (uint64) ( 1.0 / ( 1e-9 * (double) info.numer / (double) info.denom ) );
02828 }
02829 return frequency;
02830 #elif defined(AVMPLUS_UNIX)
02831 return 1000000;
02832 #else
02833 #error "need high res time impl"
02834 #endif
02835 #endif // MMGC_PORTING_API
02836 }
02837
02838 void GC::IncrementalMark()
02839 {
02840 MMGC_ASSERT_EXCLUSIVE_GC(this);
02841 uint32 time = incrementalValidation ? 1 : 5;
02842 #ifdef _DEBUG
02843 time = 1;
02844 #endif
02845
02846 SAMPLE_FRAME("[mark]", core());
02847 if(m_incrementalWork.Count() == 0 || hitZeroObjects) {
02848 FinishIncrementalMark();
02849 return;
02850 }
02851
02852 #ifdef DEBUGGER
02853 StartGCActivity();
02854 #endif
02855
02856 markIncrements++;
02857
02858 static unsigned int checkTimeIncrements = 100;
02859 uint64 start = GetPerformanceCounter();
02860
02861 #ifdef DEBUGGER
02862 numObjects=0;
02863 objSize=0;
02864 #endif
02865
02866 uint64 ticks = start + time * GetPerformanceFrequency() / 1000;
02867 do {
02868 unsigned int count = m_incrementalWork.Count();
02869 if (count == 0) {
02870 hitZeroObjects = true;
02871 break;
02872 }
02873 if (count > checkTimeIncrements) {
02874 count = checkTimeIncrements;
02875 }
02876 for(unsigned int i=0; i<count; i++)
02877 {
02878 MarkItem(m_incrementalWork);
02879 }
02880 SAMPLE_CHECK();
02881 } while(GetPerformanceCounter() < ticks);
02882
02883 lastMarkTicks = GetPerformanceCounter();
02884 markTicks += lastMarkTicks - start;
02885
02886 if(gcstats) {
02887 double millis = duration(start);
02888 uint32 kb = objSize>>10;
02889 gclog("[mem] mark(%d) %d objects (%d kb %d mb/s) in %.2f millis (%.4f s)\n",
02890 markIncrements-lastStartMarkIncrementCount, numObjects, kb,
02891 uint32(double(kb)/millis), millis, duration(t0)/1000);
02892 }
02893 }
02894
02895 void GC::FinishIncrementalMark()
02896 {
02897 MMGC_ASSERT_EXCLUSIVE_GC(this);
02898
02899
02900
02901 if (zct.reaping)
02902 {
02903 return;
02904 }
02905
02906 hitZeroObjects = false;
02907
02908
02909 sweepStart = GetPerformanceCounter();
02910
02911
02912
02913
02914 {
02915 #ifdef GCHEAP_LOCK
02916 GCAcquireSpinlock lock(m_rootListLock);
02917 #endif
02918 GCRoot *r = m_roots;
02919 while(r) {
02920 GCWorkItem item = r->GetWorkItem();
02921
02922
02923
02924 if(item.ptr) {
02925 MarkItem(item, m_incrementalWork);
02926 }
02927 r = r->next;
02928 }
02929 }
02930 MarkQueueAndStack(m_incrementalWork);
02931
02932 #ifdef _DEBUG
02933
02934
02935 FindMissingWriteBarriers();
02936 #endif
02937
02938 GCAssert(!collecting);
02939 collecting = true;
02940 GCAssert(m_incrementalWork.Count() == 0);
02941 Sweep();
02942 GCAssert(m_incrementalWork.Count() == 0);
02943 collecting = false;
02944 marking = false;
02945 }
02946
02947 int GC::IsWhite(const void *item)
02948 {
02949
02950 item = GetRealPointer((const void*) item);
02951
02952
02953 if(!IsPointerToGCPage(item))
02954 return false;
02955 int bits = GetPageMapValue((uintptr)item);
02956 switch(bits) {
02957 case 1:
02958 return GCAlloc::IsWhite(item);
02959 case 3:
02960
02961
02962
02963 return GCLargeAlloc::IsWhite(item);
02964 }
02965 return false;
02966 }
02967
02968
02969 void GC::WriteBarrierWrite(const void *address, const void *value)
02970 {
02971 GCAssert(!IsRCObject(value));
02972 *(uintptr*)address = (uintptr) value;
02973 }
02974
02975
02976 void GC::writeBarrierRC(const void *container, const void *address, const void *value)
02977 {
02978 GCAssert(IsPointerToGCPage(container));
02979 GCAssert(((uintptr)container & 3) == 0);
02980 GCAssert(((uintptr)address & 2) == 0);
02981 GCAssert(address >= container);
02982 GCAssert(address < (char*)container + Size(container));
02983
02984 WriteBarrierNoSubstitute(container, value);
02985 WriteBarrierWriteRC(address, value);
02986 }
02987
02988
02989 void GC::WriteBarrierWriteRC(const void *address, const void *value)
02990 {
02991 #ifdef MMGC_DRC
02992 RCObject *rc = (RCObject*)Pointer(*(RCObject**)address);
02993 if(rc != NULL) {
02994 GCAssert(rc == FindBeginning(rc));
02995 GCAssert(IsRCObject(rc));
02996 rc->DecrementRef();
02997 }
02998 #endif
02999 *(uintptr*)address = (uintptr) value;
03000 #ifdef MMGC_DRC
03001 rc = (RCObject*)Pointer(value);
03002 if(rc != NULL) {
03003 GCAssert(IsRCObject(rc));
03004 GCAssert(rc == FindBeginning(value));
03005 rc->IncrementRef();
03006 }
03007 #endif
03008 }
03009
03010 void GC::WriteBarrier(const void *address, const void *value)
03011 {
03012 GC* gc = GC::GetGC(address);
03013 if(Pointer(value) != NULL && gc->marking) {
03014 void *container = gc->FindBeginning(address);
03015 gc->WriteBarrierNoSubstitute(container, value);
03016 }
03017 gc->WriteBarrierWrite(address, value);
03018 }
03019
03020 void GC::WriteBarrierNoSub(const void *address, const void *value)
03021 {
03022 GC *gc = NULL;
03023 if(value != NULL && (gc = GC::GetGC(address))->marking) {
03024 void *container = gc->FindBeginning(address);
03025 gc->WriteBarrierNoSubstitute(container, value);
03026 }
03027 }
03028
03029 void GC::TrapWrite(const void *black, const void *white)
03030 {
03031
03032 (void)black;
03033 GCAssert(marking);
03034 GCAssert(GetMark(black));
03035 GCAssert(IsWhite(white));
03036
03037
03038
03039
03040
03041
03042
03043 if(ContainsPointers(white)) {
03044 SetQueued(white);
03045 PushWorkItem(m_incrementalWork, GCWorkItem(white, (uint32)Size(white), true));
03046 } else {
03047 SetMark(white);
03048 }
03049 }
03050
03051 bool GC::ContainsPointers(const void *item)
03052 {
03053 item = GetRealPointer(item);
03054 if (GCLargeAlloc::IsLargeBlock(item)) {
03055 return GCLargeAlloc::ContainsPointers(item);
03056 } else {
03057 return GCAlloc::ContainsPointers(item);
03058 }
03059 }
03060
03061 bool GC::IsGCMemory (const void *item)
03062 {
03063 int bits = GetPageMapValue((uintptr)item);
03064 return (bits != 0);
03065 }
03066
03067 bool GC::IsQueued(const void *item)
03068 {
03069 return !GetMark(item) && !IsWhite(item);
03070 }
03071
03072 uint32 *GC::GetBits(int numBytes, int sizeClass)
03073 {
03074 uint32 *bits;
03075
03076 MMGC_ASSERT_GC_LOCK(this);
03077 GCAssert(numBytes % 4 == 0);
03078
03079 #ifdef MMGC_64BIT // we use first 8-byte slot for the free list
03080 if (numBytes == 4)
03081 numBytes = 8;
03082 #endif
03083
03084
03085 if(m_bitsFreelists[sizeClass]) {
03086 bits = m_bitsFreelists[sizeClass];
03087 m_bitsFreelists[sizeClass] = *(uint32**)bits;
03088 memset(bits, 0, sizeof(uint32*));
03089 return bits;
03090 }
03091
03092 if(!m_bitsNext)
03093 m_bitsNext = (uint32*)heap->Alloc(1);
03094
03095 int leftOver = GCHeap::kBlockSize - ((uintptr)m_bitsNext & 0xfff);
03096 if(leftOver >= numBytes) {
03097 bits = m_bitsNext;
03098 if(leftOver == numBytes)
03099 m_bitsNext = 0;
03100 else
03101 m_bitsNext += numBytes/sizeof(uint32);
03102 } else {
03103 if(leftOver>=int(sizeof(void*))) {
03104
03105 for(int i=0, n=kNumSizeClasses; i<n; i++) {
03106 GCAlloc *a = noPointersAllocs[i];
03107 if(!a->m_bitsInPage && a->m_numBitmapBytes <= leftOver) {
03108 FreeBits(m_bitsNext, a->m_sizeClassIndex);
03109 break;
03110 }
03111 }
03112 }
03113 m_bitsNext = 0;
03114
03115 return GetBits(numBytes, sizeClass);
03116 }
03117 return bits;
03118 }
03119
03120 void GC::AddRoot(GCRoot *root)
03121 {
03122 #ifdef GCHEAP_LOCK
03123 GCAcquireSpinlock lock(m_rootListLock);
03124 #endif
03125 root->prev = NULL;
03126 root->next = m_roots;
03127 if(m_roots)
03128 m_roots->prev = root;
03129 m_roots = root;
03130 }
03131
03132 void GC::RemoveRoot(GCRoot *root)
03133 {
03134 #ifdef GCHEAP_LOCK
03135 GCAcquireSpinlock lock(m_rootListLock);
03136 #endif
03137 if( m_roots == root )
03138 m_roots = root->next;
03139 else
03140 root->prev->next = root->next;
03141
03142 if(root->next)
03143 root->next->prev = root->prev;
03144 }
03145
03146 void GC::AddCallback(GCCallback *cb)
03147 {
03148 USING_CALLBACK_LIST(this);
03149
03150 cb->prevCB = NULL;
03151 cb->nextCB = m_callbacks;
03152 if(m_callbacks)
03153 m_callbacks->prevCB = cb;
03154 m_callbacks = cb;
03155 }
03156
03157 void GC::RemoveCallback(GCCallback *cb)
03158 {
03159 USING_CALLBACK_LIST(this);
03160
03161 if( m_callbacks == cb )
03162 m_callbacks = cb->nextCB;
03163 else
03164 cb->prevCB->nextCB = cb->nextCB;
03165
03166 if(cb->nextCB)
03167 cb->nextCB->prevCB = cb->prevCB;
03168 }
03169
03170 void GC::PushWorkItem(GCStack<GCWorkItem> &stack, GCWorkItem item)
03171 {
03172 #ifdef RECURSIVE_MARK
03173 MarkItem(item, stack);
03174 #else
03175 if(item.ptr) {
03176 stack.Push(item);
03177 }
03178 #endif
03179 }
03180
03181 GCWeakRef* GC::GetWeakRef(const void *item)
03182 {
03183 GC *gc = GetGC(item);
03184 #ifdef MMGC_THREADSAFE
03185 GCAutoLock _lock(gc->m_lock);
03186 #endif
03187 GCWeakRef *ref = (GCWeakRef*) gc->weakRefs.get(item);
03188
03189 if(ref == NULL) {
03190 ref = new (gc) GCWeakRef(item);
03191 gc->weakRefs.put(item, ref);
03192 item = GetRealPointer(item);
03193 if (GCLargeAlloc::IsLargeBlock(item)) {
03194 GCLargeAlloc::SetHasWeakRef(item, true);
03195 } else {
03196 GCAlloc::SetHasWeakRef(item, true);
03197 }
03198 } else {
03199 GCAssert(ref->get() == item);
03200 }
03201 return ref;
03202 }
03203
03204 void GC::ClearWeakRef(const void *item)
03205 {
03206 GCWeakRef *ref = (GCWeakRef*) weakRefs.remove(item);
03207 GCAssert(weakRefs.get(item) == NULL);
03208 GCAssert(ref != NULL);
03209 GCAssert(ref->get() == item || ref->get() == NULL);
03210 if(ref) {
03211 ref->m_obj = NULL;
03212 item = GetRealPointer(item);
03213 if (GCLargeAlloc::IsLargeBlock(item)) {
03214 GCLargeAlloc::SetHasWeakRef(item, false);
03215 } else {
03216 GCAlloc::SetHasWeakRef(item, false);
03217 }
03218 }
03219 }
03220
03221 #ifdef _DEBUG
03222
03223 void GC::WhitePointerScan(const void *mem, size_t size)
03224 {
03225 uintptr *p = (uintptr *) mem;
03226
03227 uintptr *end = p + ((size) / sizeof(void*));
03228
03229 while(p < end)
03230 {
03231 uintptr val = *p;
03232 if(val == 0xdeadbeef)
03233 break;
03234 if(IsWhite((const void*) (val&~7)) &&
03235 *(((int32*)(val&~7))+1) != (int32)0xcacacaca &&
03236 *(((int32*)(val&~7))+1) != (int32)0xbabababa)
03237 {
03238 #ifdef MEMORY_INFO
03239 GCDebugMsg(false, "Object 0x%x allocated here:\n", mem);
03240 PrintStackTrace(mem);
03241 GCDebugMsg(false, "Didn't mark pointer at 0x%x, object 0x%x allocated here:\n", p, val);
03242 PrintStackTrace((const void*)(val&~7));
03243 #endif
03244 GCAssert(false);
03245 }
03246 p++;
03247 }
03248 }
03249
03250 void GC::FindMissingWriteBarriers()
03251 {
03252 MMGC_ASSERT_EXCLUSIVE_GC(this);
03253
03254 if(!incrementalValidation)
03255 return;
03256
03257 uintptr m = memStart;
03258 while(m < memEnd)
03259 {
03260
03261 int bits = GetPageMapValue(m);
03262 switch(bits)
03263 {
03264 case 0:
03265 m += GCHeap::kBlockSize;
03266 break;
03267 case 3:
03268 {
03269 GCLargeAlloc::LargeBlock *lb = (GCLargeAlloc::LargeBlock*)m;
03270 const void *item = GetUserPointer((const void*)(lb+1));
03271 if(GCLargeAlloc::GetMark(item) && GCLargeAlloc::ContainsPointers(item)) {
03272 WhitePointerScan(item, lb->usableSize - DebugSize());
03273 }
03274 m += lb->GetNumBlocks() * GCHeap::kBlockSize;
03275 }
03276 break;
03277 case 1:
03278 {
03279
03280 GCAlloc::GCBlock *b = (GCAlloc::GCBlock *) m;
03281 for (int i=0; i< b->alloc->m_itemsPerBlock; i++) {
03282
03283 if(!GCAlloc::GetBit(b, i, GCAlloc::kMark))
03284 continue;
03285
03286 if(b->alloc->ContainsPointers()) {
03287 void* item = (char*)b->items + b->alloc->m_itemSize*i;
03288 WhitePointerScan(GetUserPointer(item), b->alloc->m_itemSize - DebugSize());
03289 }
03290 }
03291 m += GCHeap::kBlockSize;
03292 }
03293 break;
03294 default:
03295 GCAssert(false);
03296 break;
03297 }
03298 }
03299 }
03300 #endif
03301
03302 #ifdef DEBUGGER
03303 void GC::StartGCActivity()
03304 {
03305
03306 USING_CALLBACK_LIST(this);
03307 GCCallback *cb = m_callbacks;
03308 while(cb) {
03309 cb->startGCActivity();
03310 cb = cb->nextCB;
03311 }
03312 }
03313
03314 void GC::StopGCActivity()
03315 {
03316
03317 USING_CALLBACK_LIST(this);
03318 GCCallback *cb = m_callbacks;
03319 while(cb) {
03320 cb->stopGCActivity();
03321 cb = cb->nextCB;
03322 }
03323 }
03324
03325 void GC::AllocActivity(int blocks)
03326 {
03327
03328 USING_CALLBACK_LIST(this);
03329 GCCallback *cb = m_callbacks;
03330 while(cb) {
03331 cb->allocActivity(blocks);
03332 cb = cb->nextCB;
03333 }
03334 }
03335 #endif
03336
03337 #if defined(MMGC_PORTING_API)
03338 uintptr_t GC::GetStackTop() const
03339 {
03340 return MMGC_PortAPI_GetStackTop();
03341 }
03342 #else
03343 #if defined(_MAC) && (defined(MMGC_IA32) || defined(MMGC_AMD64)) || defined(MMGC_MAC_NO_CARBON)
03344 uintptr GC::GetStackTop() const
03345 {
03346 return (uintptr)pthread_get_stackaddr_np(pthread_self());
03347 }
03348 #endif
03349
03350 #if defined(LINUX) && defined(MMGC_ARM) && !defined(AVMPLUS_UNIX)
03351 uintptr GC::GetStackTop() const
03352 {
03353 void* sp;
03354 pthread_attr_t attr;
03355 pthread_getattr_np(pthread_self(), &attr);
03356 pthread_attr_getstackaddr(&attr, &sp);
03357 return (uintptr)sp;
03358 }
03359 #endif
03360 #endif
03361
03362 void *GC::heapAlloc(size_t siz, bool expand, bool zero)
03363 {
03364 void *ptr = heap->Alloc((int)siz, expand, zero);
03365 if(ptr)
03366 totalGCPages += siz;
03367 return ptr;
03368 }
03369
03370 void GC::heapFree(void *ptr, size_t siz)
03371 {
03372 if(!siz)
03373 siz = heap->Size(ptr);
03374 totalGCPages -= siz;
03375 heap->Free(ptr);
03376 }
03377
03378 void GC::log_mem(const char *name, size_t bytes, size_t bytes_compare)
03379 {
03380 bytes_compare = size_t((bytes*100.0)/bytes_compare);
03381 if(bytes > 1<<20) {
03382 gclog("%s %d (%.1fM) %d%%\n", name, bytes / GCHeap::kBlockSize, bytes * 1.0 / (1024*1024), bytes_compare);
03383 } else {
03384 gclog("%s %d (%dK) %d%%\n", name, bytes / GCHeap::kBlockSize, bytes / 1024, bytes_compare);
03385 }
03386 }
03387
03388 size_t GC::GetBytesInUse()
03389 {
03390 size_t bytes=0;
03391 for(int i=0; i < kNumSizeClasses; i++) {
03392 #ifdef MMGC_DRC
03393 bytes += containsPointersRCAllocs[i]->GetBytesInUse();
03394 #endif
03395 bytes += containsPointersAllocs[i]->GetBytesInUse();
03396 bytes += noPointersAllocs[i]->GetBytesInUse();
03397 }
03398 bytes += largeAlloc->GetBytesInUse();
03399 return bytes;
03400 }
03401
03402 void GC::updateGrossMemoryStats()
03403 {
03404 size_t priv = GCHeap::GetPrivateBytes() * GCHeap::kBlockSize;
03405 size_t mmgc = heap->GetTotalHeapSize() * GCHeap::kBlockSize;
03406 size_t unmanaged = FixedMalloc::GetInstance()->GetTotalSize() * GCHeap::kBlockSize;
03407 size_t jit = (size_t)stats.get("jit") * GCHeap::kBlockSize;
03408 size_t gc_alloced = GetBytesInUse();
03409 size_t fixed_alloced = FixedMalloc::GetInstance()->GetBytesInUse();
03410 size_t gc = totalGCPages * GCHeap::kBlockSize;
03411 gclog("[mem] ------- gross stats -----\n");
03412 log_mem("[mem] private", priv, priv);
03413 log_mem("[mem]\t mmgc", mmgc, priv);
03414 log_mem("[mem]\t\t unmanaged", unmanaged, priv);
03415 log_mem("[mem]\t\t managed", gc, priv);
03416 log_mem("[mem]\t\t free", (size_t)heap->GetFreeHeapSize() * GCHeap::kBlockSize, priv);
03417 log_mem("[mem]\t jit", jit, priv);
03418 log_mem("[mem]\t other", priv - jit - mmgc, priv);
03419 log_mem("[mem] bytes (interal fragmentation)", fixed_alloced + gc_alloced, gc + unmanaged);
03420 log_mem("[mem] \tmanaged bytes ", gc_alloced, gc);
03421 log_mem("[mem] \tunmanaged bytes ", fixed_alloced, unmanaged);
03422 gclog("[mem] -------- gross stats end -----\n");
03423 }
03424
03425 #if defined (FEATURE_SAMPLER)
03426
03427 GCThreadLocal<avmplus::Sampler*> m_sampler;
03428 bool sampling = false;
03429
03430 void recordAllocationSample(void* item, size_t size, bool in_lock)
03431 {
03432 avmplus::Sampler* sampler = m_sampler;
03433 if( sampler && sampler->sampling )
03434 sampler->recordAllocationSample(item, size, !in_lock);
03435 }
03436
03437 void recordDeallocationSample(const void* item, size_t size)
03438 {
03439 avmplus::Sampler* sampler = m_sampler;
03440 if( sampler )
03441 sampler->recordDeallocationSample(item, size);
03442 }
03443 #endif
03444
03445 }