GC.h

Go to the documentation of this file.
00001 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is [Open Source Virtual Machine.].
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Adobe System Incorporated.
00019  * Portions created by the Initial Developer are Copyright (C) 2004-2006
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Adobe AS3 Team
00024  *   leon.sha@sun.com
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #ifndef __GC__
00041 #define __GC__
00042 
00043 #if defined(MMGC_PORTING_API)
00044     // When the porting API is in use, we exclude
00045     // stdlib functions or use them through
00046     // #defines for portability to platforms
00047     // that don't have them.
00048     #include "portapi_mmgc.h"
00049 #else
00050 
00051 #if defined MMGC_IA32
00052 
00053 #ifdef WIN32
00054 // save all registers: they might have pointers in them.  In theory, only
00055 // need to save callee-saved regs.  In practice, saving three extra pointers
00056 // is cheap insurance.
00057 //
00058 // These macros do not use the "do { ... } while (0)" idiom because they
00059 // work by introducing local variables (save1, save2, ...) into the block
00060 // where the macro is called.  If the macro enclosed these variables in a
00061 // nested block, like a do-while block, they would go out of scope too
00062 // soon.
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 /* On PowerPC, we need to mark the PPC non-volatile registers,
00141  * since they may contain register variables that aren't
00142  * anywhere on the machine stack. */
00143 // TPR - increasing to 20 causes this code to not get optimized out
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 // Store nonvolatile registers r4-r10
00212 // Find stack pointer
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         // If a WI is a GC item, `ptr` is the UserPointer; it must not
00263         // be the RealPointer nor an interior pointer
00264         const void *ptr;
00265 
00266         // The low bit of _size stores whether this is a GC item.
00267         // Always access this through `GetSize` and `IsGCItem`
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         // override new and delete so we can know the objects extents (via FixedMalloc::Size())
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         // called before a ZCT reap begins
00357         virtual void prereap() {}
00358 
00359         // called after a ZCT reap completes
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* /*rcobj*/) {}
00410         virtual void log(const char* /*str*/) {}
00411 
00412 #ifdef DEBUGGER
00413         virtual void startGCActivity() {}   
00414         virtual void stopGCActivity() {}
00415         // negative when blocks are reclaimed
00416         virtual void allocActivity(int /*blocks*/) {}
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         // private to prevent its use and someone adding it, GCC creates
00446         // WriteBarrier's on the stack with it
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         // how many items there have to be to trigger a Reap
00464         static const int ZCT_REAP_THRESHOLD;
00465 
00466         // size of table in pages
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         // for MMGC_GET_STACK_EXTENTS
00476         uintptr StackTop;
00477 
00478         GC *gc;
00479         void SetGC(GC*);
00480 
00481         // in pages
00482         int zctSize;
00483 
00484         // the zero count table
00485         RCObject **zct;
00486 
00487         // index to the end
00488         RCObject **zctNext;
00489 
00490         // freelist of open slots
00491         RCObject **zctFreelist;
00492 
00493         // during a reap where we are
00494         int zctIndex;
00495 
00496         // during a reap becomes zctNext
00497         int nextPinnedIndex;
00498 
00499         int count;
00500         int zctReapThreshold;
00501 
00502         // are we reaping the zct?
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         // -- Interface
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         // a tick is the unit of GetPerformanceCounter()
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         // calls to mark item
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         // called at some apropos moment from the mututor, ideally at a point
01114         // where all possible GC references will be below the current stack pointer
01115         // (ie in memory we can safely zero).  This will return right away if
01116         // called more than once between collections so it can safely be called
01117         // a lot without impacting performance
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         // for deciding a tree of things should be scanned from presweep
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         // FIXME: only used for FixedAlloc, GCAlloc sized dynamically
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         // we track the top and bottom of the stack for cleaning purposes.
01180         // the top tells us how far up the stack as been dirtied.
01181         // the bottom is also tracked so we can ensure we're on the same
01182         // stack that the GC responsible for cleaning.  necessary if multiple
01183         // threads use the GC.  only thread that creates the GC will have its stack
01184         // tracked and cleaned.
01185         bool stackCleaned;
01186         const void *rememberedStackTop;
01187         const void *rememberedStackBottom;
01188 
01189 #ifndef MMGC_THREADSAFE
01190         // for external which does thread safe multi-thread AS execution
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         // bitmap for what pages are in use, 2 bits for every page
01222         // 0 - not in use
01223         // 1 - used by GCAlloc
01224         // 3 - used by GCLargeAlloc
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         // sometimes useful for mutator to call this
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         // Deferred ref counting implementation
01448         ZCT zct;
01449         void AddToZCT(RCObject *obj) { zct.Add(obj); }
01450         // public for one hack from Interval.cpp - no one else should call
01451         // this out of the GC
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         // sent for Collect (fullgc)
01473         // and Start/IncrementalMark/Sweep for incremental
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         // methods for incremental verification
01501 
01508         void WhitePointerScan(const void *mem, size_t size);
01509 
01516         void FindMissingWriteBarriers();
01517 #ifdef WIN32
01518         // store a handle to the thread that create the GC to ensure thread safety
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         // debugging routine that records who marked who, can be used to
01529         // answer the question, how did I get marked?  also could be used to
01530         // find false positives by verifying the back pointer chain gets back
01531         // to a GC root
01532         static void WriteBackPointer(const void *item, const void *container, size_t itemSize);
01533 #endif
01534 #ifdef _DEBUG
01535         // Dump a list of objects that have pointers to the given location.
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     // helper class to wipe out vtable pointer of members for DRC
01729     class Cleaner
01730     {
01731     public:
01732         Cleaner() {}
01733         // don't let myself move between objects
01734         Cleaner& operator=(const Cleaner& /*rhs*/) { 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 /* __GC__ */

Generated on Sun Oct 12 18:50:12 2008 for Tamarin by  doxygen 1.4.6