import rt.gc.cdgc.bits: GCBits;
import rt.gc.cdgc.stats: GCStats, Stats;
import dynarray = rt.gc.cdgc.dynarray;
-import alloc = rt.gc.cdgc.alloc;
+import os = rt.gc.cdgc.os;
import opts = rt.gc.cdgc.opts;
import cstdlib = tango.stdc.stdlib;
private
{
-
- extern (C) void* rt_stackBottom();
- extern (C) void* rt_stackTop();
-
- extern (C) void rt_finalize( void* p, bool det = true );
-
alias void delegate(Object) DEvent;
- extern (C) void rt_attachDisposeEvent(Object h, DEvent e);
- extern (C) bool rt_detachDisposeEvent(Object h, DEvent e);
-
-
alias void delegate( void*, void* ) scanFn;
+ enum { OPFAIL = ~cast(size_t)0 }
- extern (C) void rt_scanStaticData( scanFn scan );
-
- extern (C) bool thread_needLock();
- extern (C) void thread_suspendAll();
- extern (C) void thread_resumeAll();
+ extern (C)
+ {
+ version (DigitalMars) version(OSX)
+ oid _d_osx_image_init();
- extern (C) void thread_scanAll( scanFn fn, void* curStackTop = null );
+ void* rt_stackBottom();
+ void* rt_stackTop();
+ void rt_finalize( void* p, bool det = true );
+ void rt_attachDisposeEvent(Object h, DEvent e);
+ bool rt_detachDisposeEvent(Object h, DEvent e);
+ void rt_scanStaticData( scanFn scan );
- extern (C) void onOutOfMemoryError();
+ void thread_init();
+ bool thread_needLock();
+ void thread_suspendAll();
+ void thread_resumeAll();
+ void thread_scanAll( scanFn fn, void* curStackTop = null );
- enum
- {
- OPFAIL = ~cast(size_t)0
+ void onOutOfMemoryError();
}
}
* Return null if not in a Pool.
* Assume pools is sorted.
*/
-Pool *findPool(void *p)
-{
- if (p >= gc.min_addr && p < gc.max_addr)
- {
- if (gc.pools.length == 1)
- {
- return gc.pools[0];
- }
-
- for (size_t i = 0; i < gc.pools.length; i++)
- {
- Pool* pool = gc.pools[i];
- if (p < pool.topAddr)
- {
- if (pool.baseAddr <= p)
- return pool;
- break;
- }
- }
- }
- return null;
-}
-
-
-/**
- * Find base address of block containing pointer p.
- * Returns null if not a gc'd pointer
- */
-void* findBase(void *p)
+Pool* findPool(void* p)
{
- Pool *pool;
-
- pool = findPool(p);
- if (pool)
- {
- size_t offset = cast(size_t)(p - pool.baseAddr);
- size_t pn = offset / PAGESIZE;
- Bins bin = cast(Bins)pool.pagetable[pn];
-
- // Adjust bit to be at start of allocated memory block
- if (bin <= B_PAGE)
- {
- return pool.baseAddr + (offset & notbinsize[bin]);
- }
- else if (bin == B_PAGEPLUS)
- {
- do
- {
- --pn, offset -= PAGESIZE;
- } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
-
- return pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1)));
- }
+ if (p < gc.min_addr || p >= gc.max_addr)
+ return null;
+ if (gc.pools.length == 0)
+ return null;
+ if (gc.pools.length == 1)
+ return gc.pools[0];
+ /// The pooltable[] is sorted by address, so do a binary search
+ size_t low = 0;
+ size_t high = gc.pools.length - 1;
+ while (low <= high) {
+ size_t mid = (low + high) / 2;
+ auto pool = gc.pools[mid];
+ if (p < pool.baseAddr)
+ high = mid - 1;
+ else if (p >= pool.topAddr)
+ low = mid + 1;
else
- {
- // we are in a B_FREE page
- return null;
- }
+ return pool;
}
+ // Not found
return null;
}
-/**
- * Find size of pointer p.
- * Returns 0 if not a gc'd pointer
- */
-size_t findSize(void *p)
-{
- Pool* pool;
- size_t size = 0;
-
- pool = findPool(p);
- if (pool)
- {
- size_t pagenum;
- Bins bin;
-
- pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
- bin = cast(Bins)pool.pagetable[pagenum];
- size = binsize[bin];
- if (bin == B_PAGE)
- {
- ubyte* pt;
- size_t i;
-
- pt = &pool.pagetable[0];
- for (i = pagenum + 1; i < pool.npages; i++)
- {
- if (pt[i] != B_PAGEPLUS)
- break;
- }
- size = (i - pagenum) * PAGESIZE;
- }
- }
- return size;
-}
-
-
/**
* Determine the base address of the block containing p. If p is not a gc
* allocated pointer, return null.
BlkInfo getInfo(void* p)
{
assert (p !is null);
-
- Pool* pool;
+ Pool* pool = findPool(p);
+ if (pool is null)
+ return BlkInfo.init;
BlkInfo info;
-
- pool = findPool(p);
- if (pool)
- {
- size_t offset = cast(size_t)(p - pool.baseAddr);
- size_t pn = offset / PAGESIZE;
- Bins bin = cast(Bins)pool.pagetable[pn];
-
- ////////////////////////////////////////////////////////////////////
- // findAddr
- ////////////////////////////////////////////////////////////////////
-
- if (bin <= B_PAGE)
- {
- info.base = pool.baseAddr + (offset & notbinsize[bin]);
+ info.base = pool.findBase(p);
+ info.size = pool.findSize(info.base);
+ info.attr = getAttr(pool, cast(size_t)(info.base - pool.baseAddr) / 16u);
+ if (has_pointermap(info.attr)) {
+ info.size -= size_t.sizeof; // PointerMap bitmask
+ // Points to the PointerMap bitmask pointer, not user data
+ if (p >= (info.base + info.size)) {
+ return BlkInfo.init;
}
- else if (bin == B_PAGEPLUS)
- {
- do
- {
- --pn, offset -= PAGESIZE;
- }
- while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
-
- info.base = pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1)));
-
- // fix bin for use by size calc below
- bin = cast(Bins)pool.pagetable[pn];
- }
-
- ////////////////////////////////////////////////////////////////////
- // findSize
- ////////////////////////////////////////////////////////////////////
-
- info.size = binsize[bin];
- if (bin == B_PAGE)
- {
- ubyte* pt;
- size_t i;
-
- pt = &pool.pagetable[0];
- for (i = pn + 1; i < pool.npages; i++)
- {
- if (pt[i] != B_PAGEPLUS)
- break;
- }
- info.size = (i - pn) * PAGESIZE;
- }
-
- ////////////////////////////////////////////////////////////////////
- // getAttr
- ////////////////////////////////////////////////////////////////////
-
- info.attr = getAttr(pool, cast(size_t)(offset / 16));
- if (!(info.attr & BlkAttr.NO_SCAN))
- info.size -= (size_t*).sizeof; // bitmask
+ }
+ if (opts.options.sentinel) {
+ info.base = sentinel_add(info.base);
+ // points to sentinel data, not user data
+ if (p < info.base || p >= sentinel_post(info.base))
+ return BlkInfo.init;
+ info.size -= SENTINEL_EXTRA;
}
return info;
}
/**
* Compute bin for size.
*/
-static Bins findBin(size_t size)
+Bins findBin(size_t size)
{
Bins bin;
if (size <= 256)
size_t type_size = pm_bitmask[0];
size_t* pm_bits = pm_bitmask + 1;
+ bool has_type_info = type_size != 1 || pm_bits[0] != 1 || pm_bits[1] != 0;
//printf("marking range: %p -> %p\n", pbot, ptop);
for (; p1 + type_size <= p2; p1 += type_size) {
for (size_t n = 0; n < type_size; n++) {
// scan bit set for this word
- if (!(pm_bits[n / BITS_PER_WORD] & (1 << (n % BITS_PER_WORD))))
+ if (has_type_info &&
+ !(pm_bits[n / BITS_PER_WORD] & (1 << (n % BITS_PER_WORD))))
continue;
void* p = *(p1 + n);
for (n = 0; n < gc.pools.length; n++)
{
pool = gc.pools[n];
+ pool.clear_cache();
uint* bbase = pool.mark.base();
size_t pn;
for (pn = 0; pn < pool.npages; pn++, bbase += PAGESIZE / (32 * 16))
else
attrs = getAttr(pool, bit_i);
- void* blk_base_addr = findBase(p);
- size_t blk_size = findSize(p);
+ void* blk_base_addr = pool.findBase(p);
+ size_t blk_size = pool.findSize(p);
bool has_pm = has_pointermap(attrs);
size_t pm_bitmask_size = 0;
if (has_pm) {
auto bit_i = cast(size_t)(p - pool.baseAddr) / 16;
uint attrs = getAttr(pool, bit_i);
- void* blk_base_addr = findBase(p);
- size_t blk_size = findSize(p);
+ void* blk_base_addr = pool.findBase(p);
+ size_t blk_size = pool.findSize(p);
bool has_pm = has_pointermap(attrs);
size_t* pm_bitmask = null;
size_t pm_bitmask_size = 0;
auto biti = cast(size_t)(p - pool.baseAddr) / 16;
uint attrs = getAttr(pool, biti);
- size_t size = findSize(p);
+ size_t size = pool.findSize(p);
size_t pm_bitmask_size = 0;
if (has_pointermap(attrs))
pm_bitmask_size = size_t.sizeof;
size_t npages;
ubyte* pagetable;
+ /// Cache for findSize()
+ size_t cached_size;
+ void* cached_ptr;
+
+ void clear_cache()
+ {
+ this.cached_ptr = null;
+ this.cached_size = 0;
+ }
void initialize(size_t npages)
{
size_t poolsize = npages * PAGESIZE;
assert(poolsize >= POOLSIZE);
- baseAddr = cast(byte *) alloc.os_mem_map(poolsize);
+ baseAddr = cast(byte *) os.alloc(poolsize);
// Some of the code depends on page alignment of memory pools
assert((cast(size_t)baseAddr & (PAGESIZE - 1)) == 0);
if (npages)
{
- result = alloc.os_mem_unmap(baseAddr, npages * PAGESIZE);
+ result = os.dealloc(baseAddr, npages * PAGESIZE);
assert(result);
npages = 0;
}
}
+ /**
+ * Find base address of block containing pointer p.
+ * Returns null if the pointer doesn't belong to this pool
+ */
+ void* findBase(void *p)
+ {
+ size_t offset = cast(size_t)(p - this.baseAddr);
+ size_t pagenum = offset / PAGESIZE;
+ Bins bin = cast(Bins)this.pagetable[pagenum];
+ // Adjust bit to be at start of allocated memory block
+ if (bin <= B_PAGE)
+ return this.baseAddr + (offset & notbinsize[bin]);
+ if (bin == B_PAGEPLUS) {
+ do {
+ --pagenum, offset -= PAGESIZE;
+ } while (cast(Bins)this.pagetable[pagenum] == B_PAGEPLUS);
+ return this.baseAddr + (offset & (offset.max ^ (PAGESIZE-1)));
+ }
+ // we are in a B_FREE page
+ return null;
+ }
+
+
+ /**
+ * Find size of pointer p.
+ * Returns 0 if p doesn't belong to this pool if if it's block size is less
+ * than a PAGE.
+ */
+ size_t findSize(void *p)
+ {
+ size_t pagenum = cast(size_t)(p - this.baseAddr) / PAGESIZE;
+ Bins bin = cast(Bins)this.pagetable[pagenum];
+ if (bin != B_PAGE)
+ return binsize[bin];
+ if (this.cached_ptr == p)
+ return this.cached_size;
+ size_t i = pagenum + 1;
+ for (; i < this.npages; i++)
+ if (this.pagetable[i] != B_PAGEPLUS)
+ break;
+ this.cached_ptr = p;
+ this.cached_size = (i - pagenum) * PAGESIZE;
+ return this.cached_size;
+ }
+
+
/**
* Used for sorting pools
*/
private int _termCleanupLevel=1;
+extern (C):
+
/// sets the cleanup level done by gc
/// 0: none
/// 1: fullCollect
/// 2: fullCollect ignoring stack roots (might crash daemonThreads)
/// result !=0 if the value was invalid
-extern (C) int gc_setTermCleanupLevel(int cLevel){
+int gc_setTermCleanupLevel(int cLevel)
+{
if (cLevel<0 || cLevel>2) return cLevel;
_termCleanupLevel=cLevel;
return 0;
}
/// returns the cleanup level done by gc
-extern (C) int gc_getTermCleanupLevel(){
+int gc_getTermCleanupLevel()
+{
return _termCleanupLevel;
}
-version (DigitalMars) version(OSX) {
- extern(C) void _d_osx_image_init();
-}
-
-extern (C) void thread_init();
-
-extern (C) void gc_init()
+void gc_init()
{
scope (exit) assert (Invariant());
gc = cast(GC*) cstdlib.calloc(1, GC.sizeof);
thread_init();
}
-extern (C) void gc_term()
+void gc_term()
{
assert (Invariant());
if (_termCleanupLevel<1) {
}
}
-extern (C) void gc_enable()
+void gc_enable()
{
return locked!(void, () {
assert (Invariant()); scope (exit) assert (Invariant());
})();
}
-extern (C) void gc_disable()
+void gc_disable()
{
return locked!(void, () {
assert (Invariant()); scope (exit) assert (Invariant());
})();
}
-extern (C) void gc_collect()
+void gc_collect()
{
return locked!(void, () {
assert (Invariant()); scope (exit) assert (Invariant());
}
-extern (C) void gc_minimize()
+void gc_minimize()
{
return locked!(void, () {
assert (Invariant()); scope (exit) assert (Invariant());
})();
}
-extern (C) uint gc_getAttr( void* p )
+uint gc_getAttr(void* p)
{
if (p is null)
return 0;
})();
}
-extern (C) uint gc_setAttr(void* p, uint attrs)
+uint gc_setAttr(void* p, uint attrs)
{
if (p is null)
return 0;
})();
}
-extern (C) uint gc_clrAttr(void* p, uint attrs)
+uint gc_clrAttr(void* p, uint attrs)
{
if (p is null)
return 0;
})();
}
-extern (C) void* gc_malloc(size_t size, uint attrs = 0,
+void* gc_malloc(size_t size, uint attrs = 0,
PointerMap ptrmap = PointerMap.init)
{
if (size == 0)
})();
}
-extern (C) void* gc_calloc(size_t size, uint attrs = 0,
+void* gc_calloc(size_t size, uint attrs = 0,
PointerMap ptrmap = PointerMap.init)
{
if (size == 0)
})();
}
-extern (C) void* gc_realloc(void* p, size_t size, uint attrs = 0,
+void* gc_realloc(void* p, size_t size, uint attrs = 0,
PointerMap ptrmap = PointerMap.init)
{
return locked!(void*, () {
})();
}
-extern (C) size_t gc_extend(void* p, size_t min_size, size_t max_size)
+size_t gc_extend(void* p, size_t min_size, size_t max_size)
{
return locked!(size_t, () {
assert (Invariant()); scope (exit) assert (Invariant());
})();
}
-extern (C) size_t gc_reserve(size_t size)
+size_t gc_reserve(size_t size)
{
if (size == 0)
return 0;
})();
}
-extern (C) void gc_free( void* p )
+void gc_free(void* p)
{
if (p is null)
return;
})();
}
-extern (C) void* gc_addrOf( void* p )
+void* gc_addrOf(void* p)
{
if (p is null)
return null;
return locked!(void*, () {
assert (Invariant()); scope (exit) assert (Invariant());
- return findBase(p);
+ Pool* pool = findPool(p);
+ if (pool is null)
+ return null;
+ return pool.findBase(p);
})();
}
-extern (C) size_t gc_sizeOf( void* p )
+size_t gc_sizeOf(void* p)
{
if (p is null)
return 0;
})();
}
-extern (C) BlkInfo gc_query( void* p )
+BlkInfo gc_query(void* p)
{
if (p is null)
return BlkInfo.init;
// NOTE: This routine is experimental. The stats or function name may change
// before it is made officially available.
-extern (C) GCStats gc_stats()
+GCStats gc_stats()
{
return locked!(GCStats, () {
assert (Invariant()); scope (exit) assert (Invariant());
})();
}
-extern (C) void gc_addRoot( void* p )
+void gc_addRoot(void* p)
{
if (p is null)
return;
})();
}
-extern (C) void gc_addRange(void* p, size_t size)
+void gc_addRange(void* p, size_t size)
{
if (p is null || size == 0)
return;
})();
}
-extern (C) void gc_removeRoot(void* p)
+void gc_removeRoot(void* p)
{
if (p is null)
return;
})();
}
-extern (C) void gc_removeRange(void* p)
+void gc_removeRange(void* p)
{
if (p is null)
return;
})();
}
-extern (C) void* gc_weakpointerCreate( Object r )
+void* gc_weakpointerCreate(Object r)
{
// weakpointers do their own locking
return weakpointerCreate(r);
}
-extern (C) void gc_weakpointerDestroy( void* wp )
+void gc_weakpointerDestroy(void* wp)
{
// weakpointers do their own locking
weakpointerDestroy(wp);
}
-extern (C) Object gc_weakpointerGet( void* wp )
+Object gc_weakpointerGet(void* wp)
{
// weakpointers do their own locking
return weakpointerGet(wp);