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 #ifndef __GC__
00041 #define __GC__
00042
00043 #if defined(MMGC_PORTING_API)
00044
00045
00046
00047
00048 #include "portapi_mmgc.h"
00049 #else
00050
00051 #if defined MMGC_IA32
00052
00053 #ifdef WIN32
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00065 int save1,save2,save3,save4,save5,save6,save7;\
00066 __asm mov save1, eax \
00067 __asm mov save2, ebx \
00068 __asm mov save3, ecx \
00069 __asm mov save4, edx \
00070 __asm mov save5, ebp \
00071 __asm mov save6, esi \
00072 __asm mov save7, edi \
00073 __asm { mov _stack,esp } ;\
00074 MEMORY_BASIC_INFORMATION __mib;\
00075 VirtualQuery(_stack, &__mib, sizeof(MEMORY_BASIC_INFORMATION)); \
00076 _size = __mib.RegionSize - ((uintptr) _stack - (uintptr)__mib.BaseAddress);
00077
00078 #elif defined SOLARIS
00079 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00080 _stack = (void *) _getsp();\
00081 _size = (uintptr)_gc->GetStackTop() - (uintptr)_stack;
00082 #else
00083 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00084 volatile auto int save1,save2,save3,save4,save5,save6,save7;\
00085 asm("movl %%eax,%0" : "=r" (save1));\
00086 asm("movl %%ebx,%0" : "=r" (save2));\
00087 asm("movl %%ecx,%0" : "=r" (save3));\
00088 asm("movl %%edx,%0" : "=r" (save4));\
00089 asm("movl %%ebp,%0" : "=r" (save5));\
00090 asm("movl %%esi,%0" : "=r" (save6));\
00091 asm("movl %%edi,%0" : "=r" (save7));\
00092 asm("movl %%esp,%0" : "=r" (_stack));\
00093 _size = (uintptr)_gc->GetStackTop() - (uintptr)_stack;
00094 #endif
00095
00096 #elif defined MMGC_AMD64
00097 #ifdef _MSC_VER // inline assembler not allowed in x64 MSVC
00098 struct saveregs {
00099 size_t save1;
00100 size_t save2;
00101 size_t save3;
00102 size_t save4;
00103 size_t save5;
00104 size_t save6;
00105 size_t save7;
00106 size_t save8;
00107 size_t save9;
00108 size_t save10;
00109 };
00110 extern "C" void saveRegs64(void* saves, const void* stack, int* size);
00111
00112 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00113 saveregs saves;\
00114 saves.save1 = 0;\
00115 saveRegs64(&saves, &_stack, (int*)&_size);
00116
00117 #else
00118 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00119 do { \
00120 volatile auto int64 save1,save2,save3,save4,save5,save6,save7,save8,save9,save10,save11,save12,save13;\
00121 asm("mov %%rax,%0" : "=r" (save1));\
00122 asm("mov %%rbx,%0" : "=r" (save2));\
00123 asm("mov %%rcx,%0" : "=r" (save3));\
00124 asm("mov %%rdx,%0" : "=r" (save4));\
00125 asm("mov %%rbp,%0" : "=r" (save5));\
00126 asm("mov %%rsi,%0" : "=r" (save6));\
00127 asm("mov %%rdi,%0" : "=r" (save7));\
00128 asm("mov %%r8,%0" : "=r" (save8));\
00129 asm("mov %%r9,%0" : "=r" (save9));\
00130 asm("mov %%r12,%0" : "=r" (save10));\
00131 asm("mov %%r13,%0" : "=r" (save11));\
00132 asm("mov %%r14,%0" : "=r" (save12));\
00133 asm("mov %%r15,%0" : "=r" (save13));\
00134 asm("mov %%rsp,%0" : "=r" (_stack));\
00135 _size = (uintptr)_gc->GetStackTop() - (uintptr)_stack; } while (0)
00136 #endif
00137
00138 #elif defined MMGC_PPC
00139
00140
00141
00142
00143
00144
00145 #ifdef __GNUC__
00146
00147 #ifdef _MAC
00148
00149 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00150 int __ppcregs[20]; \
00151 asm("stmw r13,0(%0)" : : "b" (__ppcregs));\
00152 _stack = __ppcregs;\
00153 void *__stackBase;\
00154 asm ("mr r3,r1\n"\
00155 "1: mr %0,r3\n"\
00156 "lwz r3,0(%0)\n"\
00157 "rlwinm r3,r3,0,0,30\n"\
00158 "cmpi cr0,r3,0\n"\
00159 "bne 1b" : "=b" (__stackBase) : : "r3");\
00160 _size = (uintptr) __stackBase - (uintptr) _stack;
00161
00162 #else // _MAC
00163
00164 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00165 int __ppcregs[20]; \
00166 asm("stmw %%r13,0(%0)" : : "b" (__ppcregs));\
00167 _stack = __ppcregs;\
00168 void *__stackBase;\
00169 asm ("mr %%r3,%%r1\n"\
00170 "StackBaseLoop%1%2: mr %0,%%r3\n" \
00171 "lwz %%r3,0(%0)\n"\
00172 "rlwinm %%r3,%%r3,0,0,30\n"\
00173 "cmpi cr0,%%r3,0\n"\
00174 "bne StackBaseLoop%1%2" : "=b" (__stackBase) : "i" (__FILE__), "i" (__LINE__) : "r3"); \
00175 _size = (uintptr) __stackBase - (uintptr) _stack;
00176
00177 #endif // _MAC
00178
00179 #else // __GNUC__
00180
00181 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00182 int __ppcregs[20]; \
00183 asm("stmw r13,0(%0)" : : "b" (__ppcregs));\
00184 _stack = __ppcregs;\
00185 void *__stackBase;\
00186 asm ("mr r3,r1\n"\
00187 "StackBaseLoop: mr %0,r3\n"\
00188 "lwz r3,0(%0)\n"\
00189 "rlwinm r3,r3,0,0,30\n"\
00190 "cmpi cr0,r3,0\n"\
00191 "bne StackBaseLoop" : "=b" (__stackBase) : : "r3"); \
00192 _size = (uintptr) __stackBase - (uintptr) _stack;
00193
00194 #endif // __GNUC__
00195
00196 #elif defined MMGC_ARM
00197
00198 #ifdef UNDER_CE
00199 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00200 int GC_tmp_1; void* tmp_ptr = &GC_tmp_1;\
00201 MEMORY_BASIC_INFORMATION __mib;\
00202 VirtualQuery(tmp_ptr, &__mib, sizeof(MEMORY_BASIC_INFORMATION)); \
00203 _size = __mib.RegionSize - ((int)tmp_ptr - (int)__mib.BaseAddress); \
00204 _stack = tmp_ptr;
00205 #else
00206 #ifdef __ARMCC__
00207 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00208 _stack = (void*)__current_sp(); \
00209 _size = (unsigned int*)_gc->GetStackTop() - (unsigned int*)_stack;
00210 #else
00211
00212
00213 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00214 int regs[7];\
00215 asm("stmia %0,{r4-r10}" : : "r" (regs));\
00216 asm("mov %0,sp" : "=r" (_stack));\
00217 _size = (uintptr)_gc->GetStackTop() - (uintptr)_stack;
00218 #endif //__ARMCC__
00219
00220 #endif
00221
00222
00223 #elif defined MMGC_SPARC
00224 #define MMGC_GET_STACK_EXTENTS(_gc, _stack, _size) \
00225 asm("ta 3");\
00226 _stack = (void *) _getsp();\
00227 _size = (uintptr)_gc->GetStackTop() - (uintptr)_stack;
00228 #endif
00229
00230 #ifdef MMGC_THREADSAFE
00231 #define MMGC_ASSERT_GC_LOCK(gc) GCAssert((gc)->m_lock.IsHeld() || (gc)->destroying)
00232 #define MMGC_ASSERT_EXCLUSIVE_GC(gc) \
00233 GCAssert(((gc)->m_gcRunning \
00234 && (gc)->m_exclusiveGCThread == GCThread::GetCurrentThread()) \
00235 || (gc)->destroying)
00236 #else
00237 #define MMGC_ASSERT_GC_LOCK(gc) ((void) 0)
00238 #define MMGC_ASSERT_EXCLUSIVE_GC(gc) ((void) 0)
00239 #endif
00240
00241 #endif // MMGC_PORTING_API
00242
00243 namespace avmplus
00244 {
00245 class AvmCore;
00246 }
00247
00248 namespace MMgc
00249 {
00253 class GCWorkItem
00254 {
00255 public:
00256 GCWorkItem() : ptr(NULL), _size(0) { }
00257 inline GCWorkItem(const void *p, uint32 s, bool isGCItem);
00258
00259 uint32 GetSize() const { return _size & ~1; }
00260 uint32 IsGCItem() const { return _size & 1; }
00261
00262
00263
00264 const void *ptr;
00265
00266
00267
00268 uint32 _size;
00269 };
00270
00275 class MMGC_API GCRoot
00276 {
00277 friend class GC;
00278 GCRoot();
00279 void init(GC*gc, const void *object, size_t size);
00280 public:
00282 GCRoot(GC *gc);
00284 GCRoot(GC *gc, const void *object, size_t size);
00285 virtual ~GCRoot();
00286
00287
00288 void *operator new(size_t size)
00289 {
00290 return FixedMalloc::GetInstance()->Alloc(size);
00291 }
00292
00293 void operator delete (void *object)
00294 {
00295 FixedMalloc::GetInstance()->Free(object);
00296 }
00297
00298 const void *Get() const { return object; }
00299 void Set(const void *object, size_t size);
00300
00301 GC *GetGC() const { return gc; }
00303 void Destroy();
00304
00305 private:
00306 GC * gc;
00307
00309 GCRoot *next;
00311 GCRoot *prev;
00312 const void *object;
00313 size_t size;
00314
00315 GCWorkItem GetWorkItem() const { return GCWorkItem(object, (uint32)size, false); }
00316 };
00317
00322 class MMGC_API GCCallback
00323 {
00324 friend class GC;
00325 friend class ZCT;
00326 public:
00327 GCCallback(GC *gc);
00328 virtual ~GCCallback();
00329
00330 GC *GetGC() const { return gc; }
00332 void Destroy();
00333
00341 virtual void presweep() {}
00342
00348 virtual void postsweep() {}
00349
00353 virtual void heapgrew() {}
00354
00355 #ifdef MMGC_DRC
00356
00357 virtual void prereap() {}
00358
00359
00360 virtual void postreap() {}
00361 #endif
00362
00382 virtual void enterExclusiveGC() {}
00383
00392 virtual void enterExclusiveGCNoLock() {}
00393
00404 virtual void leaveExclusiveGC() {}
00405
00409 virtual void prereap(void* ) {}
00410 virtual void log(const char* ) {}
00411
00412 #ifdef DEBUGGER
00413 virtual void startGCActivity() {}
00414 virtual void stopGCActivity() {}
00415
00416 virtual void allocActivity(int ) {}
00417 #endif
00418
00419 private:
00420 GC *gc;
00421 GCCallback *nextCB;
00422 GCCallback *prevCB;
00423 };
00424
00425 #ifdef MMGC_64BIT
00426 #define HIDDENPTRMASK (uintptr(0x1L)<<63)
00427 #else
00428 #define HIDDENPTRMASK (uintptr(0x1L)<<31)
00429 #endif
00430
00431 template <class T>
00432 class GCHiddenPointer
00433 {
00434 public:
00435 GCHiddenPointer(T obj=NULL) { set(obj); }
00436 operator T() const { return (T) (val^HIDDENPTRMASK); }
00437 T operator=(T tNew)
00438 {
00439 set(tNew);
00440 return (T)this;
00441 }
00442 T operator->() const { return (T) (val^HIDDENPTRMASK); }
00443
00444 private:
00445
00446
00447 GCHiddenPointer(const GCHiddenPointer<T>& toCopy) { GCAssert(false); }
00448
00449 void set(T obj)
00450 {
00451 uintptr p = (uintptr)obj;
00452 val = p ^ HIDDENPTRMASK;
00453 }
00454 uintptr val;
00455 };
00456
00460 class MMGC_API ZCT
00461 {
00462 friend class GC;
00463
00464 static const int ZCT_REAP_THRESHOLD;
00465
00466
00467 static const int ZCT_START_SIZE;
00468 public:
00469 ZCT();
00470 ~ZCT();
00471 void Add(RCObject *obj);
00472 void Remove(RCObject *obj);
00473 void Reap();
00474 private:
00475
00476 uintptr StackTop;
00477
00478 GC *gc;
00479 void SetGC(GC*);
00480
00481
00482 int zctSize;
00483
00484
00485 RCObject **zct;
00486
00487
00488 RCObject **zctNext;
00489
00490
00491 RCObject **zctFreelist;
00492
00493
00494 int zctIndex;
00495
00496
00497 int nextPinnedIndex;
00498
00499 int count;
00500 int zctReapThreshold;
00501
00502
00503 bool reaping;
00504
00505 void PinStackObjects(const void *start, size_t len);
00506 bool IsZCTFreelist(RCObject **obj)
00507 {
00508 return obj >= zct && obj < (RCObject**)(zct+zctSize/sizeof(RCObject*));
00509 }
00510 };
00511
00545 class MMGC_API GC : public GCAllocObject
00546 {
00547 friend class GCRoot;
00548 friend class GCCallback;
00549 friend class GCAlloc;
00550 friend class GCLargeAlloc;
00551 friend class RCObject;
00552 friend class GCInterval;
00553 friend class ZCT;
00554 public:
00555
00559 enum
00560 {
00561 GCV_COREPLAYER,
00562 GCV_AVMCORE,
00563 GCV_COUNT
00564 };
00565 void *GetGCContextVariable(int var) const { return m_contextVars[var]; }
00566 void SetGCContextVariable(int var, void *val) { m_contextVars[var] = val; }
00567
00568 avmplus::AvmCore *core() const { return (avmplus::AvmCore*)GetGCContextVariable(GCV_AVMCORE); }
00569
00581 bool greedy;
00582
00589 bool nogc;
00590
00594 bool findUnmarkedPointers;
00595
00600 bool validateDefRef;
00601 bool keepDRCHistory;
00602
00613 size_t collectThreshold;
00614
00625 bool gcstats;
00626
00627 bool dontAddToZCTDuringCollection;
00628 bool incrementalValidation;
00629
00630 #ifdef _DEBUG
00631 bool incrementalValidationPedantic;
00632 #endif
00633
00642 bool incremental;
00643
00644
00645 GC(GCHeap *heap);
00646 ~GC();
00647
00657 void Collect();
00658
00671 void MaybeGC(bool callerHasActiveRequest=false);
00672
00676 enum AllocFlags
00677 {
00678 kZero=1,
00679 kContainsPointers=2,
00680 kFinalize=4,
00681 kRCObject=8
00682 };
00683
00684 enum PageType
00685 {
00686 kNonGC = 0,
00687 kGCAllocPage = 1,
00688 kGCLargeAllocPageRest = 2,
00689 kGCLargeAllocPageFirst = 3
00690 };
00691
00700 void *Alloc(size_t size, int flags=0);
00701
00703 void *AllocAlreadyLocked(size_t size, int flags=0);
00704
00705
00715 void *Calloc(size_t num, size_t elsize, int flags=0);
00716
00724 void Free(const void *ptr);
00725
00731 static size_t Size(const void *ptr)
00732 {
00733 GCAssert(GetGC(ptr)->IsGCMemory(ptr));
00734 size_t size = GCLargeAlloc::GetBlockHeader(ptr)->usableSize;
00735 size -= DebugSize();
00736 return size;
00737
00738 }
00739
00746 static int GetMark(const void *item);
00747
00748 static int SetMark(const void *item)
00749 {
00750 GCAssert(item != NULL);
00751 #ifdef MEMORY_INFO
00752 GC *gc = GetGC(item);
00753 item = GetRealPointer(item);
00754 GCAssert(gc->IsPointerToGCPage(item));
00755 #endif
00756 if (GCLargeAlloc::IsLargeBlock(item)) {
00757 return GCLargeAlloc::SetMark(item);
00758 } else {
00759 return GCAlloc::SetMark(item);
00760 }
00761 }
00762
00763 void SetQueued(const void *item)
00764 {
00765 #ifdef MEMORY_INFO
00766 item = GetRealPointer(item);
00767 GCAssert(IsPointerToGCPage(item));
00768 #endif
00769 if (GCLargeAlloc::IsLargeBlock(item)) {
00770 GCLargeAlloc::SetQueued(item);
00771 } else {
00772 GCAlloc::SetQueued(item);
00773 }
00774 }
00775
00776 static void ClearFinalized(const void *item)
00777 {
00778 #ifdef MEMORY_INFO
00779 GC *gc = GetGC(item);
00780 item = GetRealPointer(item);
00781 GCAssert(gc->IsPointerToGCPage(item));
00782 #endif
00783 if (GCLargeAlloc::IsLargeBlock(item)) {
00784 GCLargeAlloc::ClearFinalized(item);
00785 } else {
00786 GCAlloc::ClearFinalized(item);
00787 }
00788 }
00789
00790 static void SetFinalize(const void *item)
00791 {
00792 #ifdef MEMORY_INFO
00793 GC *gc = GetGC(item);
00794 item = GetRealPointer(item);
00795 GCAssert(gc->IsPointerToGCPage(item));
00796 #endif
00797 if (GCLargeAlloc::IsLargeBlock(item)) {
00798 GCLargeAlloc::SetFinalize(item);
00799 } else {
00800 GCAlloc::SetFinalize(item);
00801 }
00802 }
00803
00804 static int IsFinalized(const void *item)
00805 {
00806 #ifdef MEMORY_INFO
00807 GC *gc = GetGC(item);
00808 item = GetRealPointer(item);
00809 GCAssert(gc->IsPointerToGCPage(item));
00810 #endif
00811 if (GCLargeAlloc::IsLargeBlock(item)) {
00812 return GCLargeAlloc::IsFinalized(item);
00813 } else {
00814 return GCAlloc::IsFinalized(item);
00815 }
00816 }
00817
00818 static int HasWeakRef(const void *item)
00819 {
00820 #ifdef MEMORY_INFO
00821 GC *gc = GetGC(item);
00822 item = GetRealPointer(item);
00823 GCAssert(gc->IsPointerToGCPage(item));
00824 #endif
00825 if (GCLargeAlloc::IsLargeBlock(item)) {
00826 return GCLargeAlloc::HasWeakRef(item);
00827 } else {
00828 return GCAlloc::HasWeakRef(item);
00829 }
00830 }
00831
00836 static GC* GetGC(const void *item)
00837 {
00838 GC **gc = (GC**) ((uintptr)item&~0xfff);
00839 return *gc;
00840 }
00841
00847 void* AllocBlock(int size, int pageType, bool zero=true);
00848
00850 void FreeBlock(void *ptr, uint32 size);
00851
00852 GCHeap *GetGCHeap() const { return heap; }
00853
00854 #ifdef MMGC_DRC
00855 void ReapZCT() { zct.Reap(); }
00856 bool Reaping() { return zct.reaping; }
00857 #ifdef _DEBUG
00858 void RCObjectZeroCheck(RCObject *);
00859 #endif
00860 #endif
00861
00865 bool IsPointerToGCPage(const void *item);
00866
00870 void IncrementalMark();
00871
00875 bool IncrementalMarking() { return marking; }
00876
00884 static void WriteBarrier(const void *address, const void *value);
00885
00887 static void WriteBarrierNoSub(const void *address, const void *value);
00888
00890 void writeBarrier(const void *container, const void *address, const void *value)
00891 {
00892 GCAssert(!container || IsPointerToGCPage(container));
00893 GCAssert(((uintptr)address & 3) == 0);
00894
00895 if (container) {
00896 GCAssert(address >= container);
00897 GCAssert(address < (char*)container + Size(container));
00898 WriteBarrierNoSubstitute(container, value);
00899 }
00900 WriteBarrierWrite(address, value);
00901 }
00902
00908 void writeBarrierRC(const void *container, const void *address, const void *value);
00909
00917 __forceinline void WriteBarrierNoSubstitute(const void *container, const void *value)
00918 {
00919 WriteBarrierTrap(container, (const void*)((uintptr)value&~7));
00920 }
00921
00928 __forceinline void WriteBarrierTrap(const void *container, const void *valuePtr)
00929 {
00930 GCAssert(IsPointerToGCPage(container));
00931 GCAssert(((uintptr)valuePtr&7) == 0);
00932 GCAssert(IsPointerToGCPage(container));
00933 if(marking && valuePtr && GetMark(container) && IsWhite(valuePtr))
00934 {
00935 TrapWrite(container, valuePtr);
00936 }
00937 }
00938
00939 void ConservativeWriteBarrierNoSubstitute(const void *address, const void *value)
00940 {
00941 if(IsPointerToGCPage(address))
00942 WriteBarrierNoSubstitute(FindBeginning(address), value);
00943 }
00944
00945 private:
00946 __forceinline void WriteBarrierWrite(const void *address, const void *value);
00947 __forceinline void WriteBarrierWriteRC(const void *address, const void *value);
00948
00949 public:
00950
00952 bool ContainsPointers(const void *item);
00953
00955 void *FindBeginning(const void *gcItem)
00956 {
00957 GCAssert(gcItem != NULL);
00958 GCAssert(GetPageMapValue((uintptr)gcItem) != 0);
00959 void *realItem = NULL;
00960 if((uintptr)gcItem < memStart || (uintptr)gcItem >= memEnd)
00961 return NULL;
00962 int bits = GetPageMapValue((uintptr)gcItem);
00963 switch(bits)
00964 {
00965 case kGCAllocPage:
00966 realItem = GCAlloc::FindBeginning(gcItem);
00967 break;
00968 case kGCLargeAllocPageFirst:
00969 realItem = GCLargeAlloc::FindBeginning(gcItem);
00970 break;
00971 case kGCLargeAllocPageRest:
00972 while(bits == kGCLargeAllocPageRest)
00973 {
00974 gcItem = (void*) ((uintptr)gcItem - GCHeap::kBlockSize);
00975 bits = GetPageMapValue((uintptr)gcItem);
00976 }
00977 realItem = GCLargeAlloc::FindBeginning(gcItem);
00978 break;
00979 default:
00980 return NULL;
00981 }
00982 #ifdef MEMORY_INFO
00983 realItem = GetUserPointer(realItem);
00984 #endif
00985 return realItem;
00986 }
00987
00988 #ifdef MMGC_DRC
00989 bool IsRCObject(const void *);
00990 #else
00991 bool IsRCObject(const void *) { return false; }
00992 #endif
00993
01002 bool Collecting() const
01003 {
01004 return collecting;
01005 }
01006
01008 bool IsGCMemory (const void *);
01009
01011 bool IsQueued(const void *item);
01012
01013 static uint64 GetPerformanceCounter();
01014 static uint64 GetPerformanceFrequency();
01015
01016 static double duration(uint64 start)
01017 {
01018 return (double(GC::GetPerformanceCounter() - start) * 1000) / GC::GetPerformanceFrequency();
01019 }
01020
01021 #ifndef MMGC_THREADSAFE
01022 void DisableThreadCheck() { disableThreadCheck = true; }
01023 #endif
01024
01026 const uint64 t0;
01027
01028
01029 static uint64 ticksToMicros(uint64 ticks)
01030 {
01031 #ifdef WIN32
01032 return (ticks*1000000)/GetPerformanceFrequency();
01033 #else
01034 return ticks;
01035 #endif
01036 }
01037
01038
01039 static uint64 ticksToMillis(uint64 ticks)
01040 {
01041 #ifdef WIN32
01042 return (ticks*1000)/GetPerformanceFrequency();
01043 #else
01044 return ticks/1000;
01045 #endif
01046 }
01047
01055 uint64 bytesMarked;
01056
01063 uint64 markTicks;
01064
01065
01066 uint32 lastStartMarkIncrementCount;
01067 uint32 markIncrements;
01068
01073 uint32 marks;
01074
01079 uint32 sweeps;
01080
01087 uint32 numObjects;
01088
01095 uint32 objSize;
01096
01102 uint64 sweepStart;
01103
01111 bool hitZeroObjects;
01112
01113
01114
01115
01116
01117
01118 void CleanStack(bool force=false);
01119
01120 bool Destroying() { return destroying; }
01121
01123 static GCWeakRef *GetWeakRef(const void *obj);
01124
01126 void ClearWeakRef(const void *obj);
01127
01128 uintptr GetStackTop() const;
01129
01130
01131 void PushWorkItem(GCWorkItem &item) { PushWorkItem(m_incrementalWork, item); }
01132
01133 private:
01134
01135 void *heapAlloc(size_t size, bool expand=true, bool zero=true);
01136 void heapFree(void *ptr, size_t siz=0);
01137
01138 void gclog(const char *format, ...);
01139 void log_mem(const char *name, size_t s, size_t comp );
01140
01141 const static int kNumSizeClasses = 40;
01142
01143
01144 const static int kPageUsableSpace = 3936;
01145
01147 uint32 *GetBits(int numBytes, int sizeClass);
01148
01150 void FreeBits(uint32 *bits, int sizeClass)
01151 {
01152 #ifdef _DEBUG
01153 for(int i=0, n=noPointersAllocs[sizeClass]->m_numBitmapBytes; i<n;i++) GCAssert(((uint8*)bits)[i] == 0);
01154 #endif
01155 *(uint32**)bits = m_bitsFreelists[sizeClass];
01156 m_bitsFreelists[sizeClass] = bits;
01157 }
01158
01160 uint32 *m_bitsFreelists[kNumSizeClasses];
01162 uint32 *m_bitsNext;
01163
01165 GCHashtable weakRefs;
01166
01167 bool destroying;
01168
01177 size_t heapSizeAtLastAlloc;
01178
01179
01180
01181
01182
01183
01184
01185 bool stackCleaned;
01186 const void *rememberedStackTop;
01187 const void *rememberedStackBottom;
01188
01189 #ifndef MMGC_THREADSAFE
01190
01191 bool disableThreadCheck;
01192 #endif
01193
01203 bool marking;
01204 GCStack<GCWorkItem> m_incrementalWork;
01205 void StartIncrementalMark();
01206 void FinishIncrementalMark();
01207
01209 int IsWhite(const void *item);
01210
01212 uint64 lastMarkTicks;
01214 uint64 lastSweepTicks;
01215
01216 const static int16 kSizeClasses[kNumSizeClasses];
01217 const static uint8 kSizeClassIndex[246];
01218
01219 void *m_contextVars[GCV_COUNT];
01220
01221
01222
01223
01224
01225
01227 uintptr memStart;
01229 uintptr memEnd;
01230
01232 size_t totalGCPages;
01233
01234 GCHashtable stats;
01235 void updateGrossMemoryStats();
01236
01251 unsigned char *pageMap;
01252
01256 #ifdef MMGC_THREADSAFE
01257 mutable GCSpinLock pageMapLock;
01258 #endif
01259
01260 inline int GetPageMapValue(uintptr addr) const
01261 {
01262 #ifdef MMGC_THREADSAFE
01263 GCAcquireSpinlock lock(pageMapLock);
01264 #endif
01265 return GetPageMapValueAlreadyLocked(addr);
01266 }
01267
01269 int GetPageMapValueAlreadyLocked(uintptr addr) const;
01270
01277 void SetPageMapValue(uintptr addr, int val);
01278
01284 void ClearPageMapValue(uintptr addr);
01285
01286 void MarkGCPages(void *item, uint32 numpages, int val);
01287 void UnmarkGCPages(void *item, uint32 numpages);
01288
01293 void ConservativeMarkRegion(const void *base, size_t bytes);
01294
01295 GCAlloc *containsPointersAllocs[kNumSizeClasses];
01296 #ifdef MMGC_DRC
01297 GCAlloc *containsPointersRCAllocs[kNumSizeClasses];
01298 #endif
01299 GCAlloc *noPointersAllocs[kNumSizeClasses];
01300 GCLargeAlloc *largeAlloc;
01301 GCHeap *heap;
01302
01304 void* AllocBlockIncremental(int size, bool zero=true);
01305
01307 void* AllocBlockNonIncremental(int size, bool zero=true);
01308
01309 protected:
01319 void CollectWithBookkeeping(bool callerHoldsLock,
01320 bool callerHasActiveRequest);
01321
01322 private:
01328 void CollectImpl();
01329
01330 #ifdef _DEBUG
01331 public:
01332 #endif
01333
01334 void ClearMarks();
01335 #ifdef _DEBUG
01336 private:
01337 #endif
01338
01339
01340 #ifdef _DEBUG
01341 public:
01342
01344 void Trace(const void *stackStart=NULL, uint32 stackSize=0);
01345 private:
01346 #endif
01347
01349 void Finalize();
01351 void Sweep(bool force=false);
01353 void ForceSweep() { Sweep(true); }
01355 void Mark(GCStack<GCWorkItem> &work);
01357 void MarkQueueAndStack(GCStack<GCWorkItem> &work);
01359 void MarkItem(GCStack<GCWorkItem> &work)
01360 {
01361 GCWorkItem workitem = work.Pop();
01362 MarkItem(workitem, work);
01363 }
01365 void MarkItem(GCWorkItem &workitem, GCStack<GCWorkItem> &work);
01366
01372 void TrapWrite(const void *black, const void *white);
01373
01380 unsigned int allocsSinceCollect;
01381
01393 bool collecting;
01394
01396 bool finalizedValue;
01397
01399 void AddToSmallEmptyBlockList(GCAlloc::GCBlock *b)
01400 {
01401 b->next = smallEmptyPageList;
01402 smallEmptyPageList = b;
01403 }
01404
01409 GCAlloc::GCBlock *smallEmptyPageList;
01410
01412 void AddToLargeEmptyBlockList(GCLargeAlloc::LargeBlock *lb)
01413 {
01414 lb->next = largeEmptyPageList;
01415 largeEmptyPageList = lb;
01416 }
01417
01422 GCLargeAlloc::LargeBlock *largeEmptyPageList;
01423
01424 #ifdef GCHEAP_LOCK
01425 GCSpinLock m_rootListLock;
01426 #endif
01427
01429 GCRoot *m_roots;
01430 void AddRoot(GCRoot *root);
01431 void RemoveRoot(GCRoot *root);
01432
01433 #ifdef MMGC_THREADSAFE
01434 GCSpinLock m_callbackListLock;
01435 #endif
01436
01442 GCCallback *m_callbacks;
01443 void AddCallback(GCCallback *cb);
01444 void RemoveCallback(GCCallback *cb);
01445
01446 #ifdef MMGC_DRC
01447
01448 ZCT zct;
01449 void AddToZCT(RCObject *obj) { zct.Add(obj); }
01450
01451
01452 public:
01453 void RemoveFromZCT(RCObject *obj) { zct.Remove(obj); }
01454 private:
01455 #endif
01456
01457 static const void *Pointer(const void *p) { return (const void*)(((uintptr)p)&~7); }
01458
01459 #ifdef MEMORY_INFO
01460 public:
01461 void DumpMemoryInfo();
01462 private:
01463 #endif
01464
01465 #ifndef MMGC_THREADSAFE
01466 void CheckThread();
01467 #endif
01468
01469 void PushWorkItem(GCStack<GCWorkItem> &stack, GCWorkItem item);
01470
01471 #ifdef DEBUGGER
01472
01473
01474 void StartGCActivity();
01475 void StopGCActivity();
01476 void AllocActivity(int blocks);
01477 #endif
01478
01479 #ifdef _DEBUG
01480 void CheckFreelist(GCAlloc *gca);
01481 void CheckFreelists();
01482
01483
01484 int m_gcLastStackTrace;
01485
01491 void UnmarkedScan(const void *mem, size_t size);
01492
01498 void FindUnmarkedPointers();
01499
01500
01501
01508 void WhitePointerScan(const void *mem, size_t size);
01509
01516 void FindMissingWriteBarriers();
01517 #ifdef WIN32
01518
01519 DWORD m_gcThread;
01520 #endif
01521 #endif
01522
01523 public:
01524 #ifdef MEMORY_INFO
01525 typedef void (*pDumpBackCallbackProc)(void* pContext, void *obj, const char *type );
01526 void DumpBackPointerChain(void *o, pDumpBackCallbackProc p = NULL, void *context = NULL);
01527
01528
01529
01530
01531
01532 static void WriteBackPointer(const void *item, const void *container, size_t itemSize);
01533 #endif
01534 #ifdef _DEBUG
01535
01536 void WhosPointingAtMe(void* me, int recurseDepth=0, int currentDepth=0);
01537
01542 void ProbeForMatch(const void *mem, size_t size, uintptr value, int recurseDepth, int currentDepth);
01543 #endif
01544
01545 void UpdateStat(const char *key, int delta)
01546 {
01547 stats.put(key, (const void*)((size_t)stats.get(key) + delta));
01548 }
01549
01550 size_t GetBytesInUse();
01551
01552 #ifdef MMGC_THREADSAFE
01553 public:
01563 bool IsGCRunning() const { return m_gcRunning; }
01564
01565 protected:
01567 void OnEnterRequestAlreadyLocked()
01568 {
01569 WaitForGCDone();
01570 m_requestCount++;
01571 #ifdef _DEBUG
01572 GCThread::GetCurrentThread()->OnEnterRequest();
01573 #endif
01574 }
01575
01577 void OnLeaveRequestAlreadyLocked()
01578 {
01579 GCAssert(m_requestCount > 0);
01580 m_requestCount--;
01581 if (m_requestCount == 0)
01582 m_condNoRequests.NotifyAll();
01583 #ifdef _DEBUG
01584 GCThread::GetCurrentThread()->OnLeaveRequest();
01585 #endif
01586 }
01587
01588 public:
01593 void OnEnterRequest()
01594 {
01595 GCAutoLock _lock(m_lock);
01596 OnEnterRequestAlreadyLocked();
01597 }
01598
01603 void OnLeaveRequest()
01604 {
01605 GCAutoLock _lock(m_lock);
01606 OnLeaveRequestAlreadyLocked();
01607 }
01608
01615 void CollectFromRequest()
01616 {
01617 CollectWithBookkeeping(false, true);
01618 }
01619
01620 protected:
01626 void WaitForGCDone()
01627 {
01628 GCAssert(m_exclusiveGCThread != GCThread::GetCurrentThread());
01629 while (m_exclusiveGCThread != NULL)
01630 m_condDone.Wait();
01631 }
01632
01679 mutable GCLock m_lock;
01680
01687 GCThread *m_exclusiveGCThread;
01688
01699 bool m_gcRunning;
01700
01706 GCCondition m_condDone;
01707
01713 int m_requestCount;
01714
01724 GCCondition m_condNoRequests;
01725 #endif
01726 };
01727
01728
01729 class Cleaner
01730 {
01731 public:
01732 Cleaner() {}
01733
01734 Cleaner& operator=(const Cleaner& ) { return *this; }
01735 void set(const void * _v, size_t _size) { this->v = (int*)_v; this->size = _size; }
01736 ~Cleaner() {
01737 if(v)
01738 memset(v, 0, size);
01739 v = 0;
01740 size = 0;
01741 }
01742 int *v;
01743 size_t size;
01744 };
01745
01746 inline GCWorkItem::GCWorkItem(const void *p, uint32 s, bool isGCItem)
01747 : ptr(p)
01748 , _size(s | uint32(isGCItem))
01749 {
01750 #ifdef _DEBUG
01751 if (IsGCItem()) {
01752 GCAssert(GC::GetGC(p)->FindBeginning(p) == p);
01753 }
01754 #endif
01755 }
01756 }
01757
01758 #endif