X-Git-Url: https://git.llucax.com/software/dgc/cdgc.git/blobdiff_plain/004b7e95d7c07045ff197463abf3eab1e9d353ac..39229a694674a24ad2d3b9203f591198b7c60ca7:/rt/gc/cdgc/gc.d diff --git a/rt/gc/cdgc/gc.d b/rt/gc/cdgc/gc.d index 1c99055..b9973b8 100644 --- a/rt/gc/cdgc/gc.d +++ b/rt/gc/cdgc/gc.d @@ -30,11 +30,7 @@ module rt.gc.cdgc.gc; /************** Debugging ***************************/ -//debug = PRINTF; // turn on printf's //debug = COLLECT_PRINTF; // turn on printf's -//debug = LOGGING; // log allocations / frees -//debug = MEMSTOMP; // stomp on memory -//debug = SENTINEL; // add underrun/overrrun protection //debug = PTRCHECK; // more pointer checking //debug = PTRCHECK2; // thorough but slow pointer checking @@ -46,11 +42,31 @@ version = STACKGROWSDOWN; // growing the stack means subtracting from the /***************************************************/ -import rt.gc.cdgc.bits; -import rt.gc.cdgc.stats; -import rt.gc.cdgc.alloc; -import rt.gc.cdgc.libc; +import rt.gc.cdgc.bits: GCBits; +import rt.gc.cdgc.stats: GCStats, Stats; +import rt.gc.cdgc.dynarray: DynArray; +import alloc = rt.gc.cdgc.alloc; +import opts = rt.gc.cdgc.opts; +import cstdlib = tango.stdc.stdlib; +import cstring = tango.stdc.string; + +/* + * This is a small optimization that proved it's usefulness. For small chunks + * or memory memset() seems to be slower (probably because of the call) that + * simply doing a simple loop to set the memory. + */ +void memset(void* dst, int c, size_t n) +{ + // This number (32) has been determined empirically + if (n > 32) { + cstring.memset(dst, c, n); + return; + } + auto p = cast(ubyte*)(dst); + while (n-- > 0) + *p++ = c; +} version (GNU) { @@ -58,10 +74,9 @@ version (GNU) // subdirectory is elsewhere. Instead, perhaps the functions // could be declared directly or some other resolution could // be found. - import gcc.builtins; // for __builtin_unwind_init + static import gcc.builtins; // for __builtin_unwind_int } - struct BlkInfo { void* base; @@ -69,15 +84,16 @@ struct BlkInfo uint attr; } +package enum BlkAttr : uint +{ + FINALIZE = 0b0000_0001, + NO_SCAN = 0b0000_0010, + NO_MOVE = 0b0000_0100, + ALL_BITS = 0b1111_1111 +} + private { - enum BlkAttr : uint - { - FINALIZE = 0b0000_0001, - NO_SCAN = 0b0000_0010, - NO_MOVE = 0b0000_0100, - ALL_BITS = 0b1111_1111 - } extern (C) void* rt_stackBottom(); extern (C) void* rt_stackTop(); @@ -111,106 +127,6 @@ private alias GC gc_t; -/* ======================= Leak Detector =========================== */ - - -debug (LOGGING) -{ - struct Log - { - void* p; - size_t size; - size_t line; - char* file; - void* parent; - - void print() - { - printf(" p = %x, size = %d, parent = %x ", p, size, parent); - if (file) - { - printf("%s(%u)", file, line); - } - printf("\n"); - } - } - - - struct LogArray - { - size_t dim; - size_t allocdim; - Log *data; - - void Dtor() - { - if (data) - .free(data); - data = null; - } - - void reserve(size_t nentries) - { - assert(dim <= allocdim); - if (allocdim - dim < nentries) - { - allocdim = (dim + nentries) * 2; - assert(dim + nentries <= allocdim); - if (!data) - { - data = cast(Log*) .malloc(allocdim * Log.sizeof); - if (!data && allocdim) - onOutOfMemoryError(); - } - else - { Log *newdata; - - newdata = cast(Log*) .malloc(allocdim * Log.sizeof); - if (!newdata && allocdim) - onOutOfMemoryError(); - .memcpy(newdata, data, dim * Log.sizeof); - .free(data); - data = newdata; - } - } - } - - - void push(Log log) - { - reserve(1); - data[dim++] = log; - } - - void remove(size_t i) - { - .memmove(data + i, data + i + 1, (dim - i) * Log.sizeof); - dim--; - } - - - size_t find(void *p) - { - for (size_t i = 0; i < dim; i++) - { - if (data[i].p == p) - return i; - } - return OPFAIL; // not found - } - - - void copy(LogArray *from) - { - reserve(from.dim - dim); - assert(from.dim <= allocdim); - .memcpy(data, from.data, from.dim * Log.sizeof); - dim = from.dim; - } - } -} - - /* ============================ GC =============================== */ @@ -220,6 +136,8 @@ class GCLock { } // just a dummy so we can get a global lock const uint GCVERSION = 1; // increment every time we change interface // to GC. +Stats stats; + class GC { // For passing to debug code @@ -234,23 +152,14 @@ class GC void initialize() { + opts.parse(cstdlib.getenv("D_GC_OPTS")); gcLock = GCLock.classinfo; - gcx = cast(Gcx*) .calloc(1, Gcx.sizeof); + gcx = cast(Gcx*) cstdlib.calloc(1, Gcx.sizeof); if (!gcx) onOutOfMemoryError(); gcx.initialize(); setStackBottom(rt_stackBottom()); - } - - - void Dtor() - { - if (gcx) - { - gcx.Dtor(); - .free(gcx); - gcx = null; - } + stats = Stats(this); } @@ -301,15 +210,15 @@ class GC uint go() { Pool* pool = gcx.findPool(p); - uint oldb = 0; + uint old_attrs = 0; if (pool) { - auto biti = cast(size_t)(p - pool.baseAddr) / 16; + auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; - oldb = gcx.getBits(pool, biti); + old_attrs = gcx.getAttr(pool, bit_i); } - return oldb; + return old_attrs; } if (!thread_needLock()) @@ -336,16 +245,16 @@ class GC uint go() { Pool* pool = gcx.findPool(p); - uint oldb = 0; + uint old_attrs = 0; if (pool) { - auto biti = cast(size_t)(p - pool.baseAddr) / 16; + auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; - oldb = gcx.getBits(pool, biti); - gcx.setBits(pool, biti, mask); + old_attrs = gcx.getAttr(pool, bit_i); + gcx.setAttr(pool, bit_i, mask); } - return oldb; + return old_attrs; } if (!thread_needLock()) @@ -372,16 +281,16 @@ class GC uint go() { Pool* pool = gcx.findPool(p); - uint oldb = 0; + uint old_attrs = 0; if (pool) { - auto biti = cast(size_t)(p - pool.baseAddr) / 16; + auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; - oldb = gcx.getBits(pool, biti); - gcx.clrBits(pool, biti, mask); + old_attrs = gcx.getAttr(pool, bit_i); + gcx.clrAttr(pool, bit_i, mask); } - return oldb; + return old_attrs; } if (!thread_needLock()) @@ -398,7 +307,7 @@ class GC /** * */ - void *malloc(size_t size, uint bits = 0) + void *malloc(size_t size, uint attrs = 0) { if (!size) { @@ -407,11 +316,11 @@ class GC if (!thread_needLock()) { - return mallocNoSync(size, bits); + return mallocNoSync(size, attrs); } else synchronized (gcLock) { - return mallocNoSync(size, bits); + return mallocNoSync(size, attrs); } } @@ -419,17 +328,21 @@ class GC // // // - private void *mallocNoSync(size_t size, uint bits = 0) + private void *mallocNoSync(size_t size, uint attrs = 0) { assert(size != 0); + stats.malloc_started(size, attrs); + scope (exit) + stats.malloc_finished(); + void *p = null; Bins bin; - //debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p)\n", size, gcx); assert(gcx); - size += SENTINEL_EXTRA; + if (opts.options.sentinel) + size += SENTINEL_EXTRA; // Compute size bin // Cache previous binsize lookup - Dave Fladebo. @@ -468,10 +381,9 @@ class GC } } if (!gcx.bucket[bin] && !gcx.allocPage(bin)) - { int result; - + { gcx.newPool(1); // allocate new pool to find a new page - result = gcx.allocPage(bin); + int result = gcx.allocPage(bin); if (!result) onOutOfMemoryError(); } @@ -480,10 +392,10 @@ class GC // Return next item from free list gcx.bucket[bin] = (cast(List*)p).next; - if( !(bits & BlkAttr.NO_SCAN) ) - .memset(p + size, 0, binsize[bin] - size); - //debug(PRINTF) printf("\tmalloc => %x\n", p); - debug (MEMSTOMP) .memset(p, 0xF0, size); + if( !(attrs & BlkAttr.NO_SCAN) ) + memset(p + size, 0, binsize[bin] - size); + if (opts.options.mem_stomp) + memset(p, 0xF0, size); } else { @@ -491,17 +403,18 @@ class GC if (!p) onOutOfMemoryError(); } - size -= SENTINEL_EXTRA; - p = sentinel_add(p); - sentinel_init(p, size); - gcx.log_malloc(p, size); + if (opts.options.sentinel) { + size -= SENTINEL_EXTRA; + p = sentinel_add(p); + sentinel_init(p, size); + } - if (bits) + if (attrs) { Pool *pool = gcx.findPool(p); assert(pool); - gcx.setBits(pool, cast(size_t)(p - pool.baseAddr) / 16, bits); + gcx.setAttr(pool, cast(size_t)(p - pool.baseAddr) / 16, attrs); } return p; } @@ -510,7 +423,7 @@ class GC /** * */ - void *calloc(size_t size, uint bits = 0) + void *calloc(size_t size, uint attrs = 0) { if (!size) { @@ -519,11 +432,11 @@ class GC if (!thread_needLock()) { - return callocNoSync(size, bits); + return callocNoSync(size, attrs); } else synchronized (gcLock) { - return callocNoSync(size, bits); + return callocNoSync(size, attrs); } } @@ -531,13 +444,12 @@ class GC // // // - private void *callocNoSync(size_t size, uint bits = 0) + private void *callocNoSync(size_t size, uint attrs = 0) { assert(size != 0); - //debug(PRINTF) printf("calloc: %x len %d\n", p, len); - void *p = mallocNoSync(size, bits); - .memset(p, 0, size); + void *p = mallocNoSync(size, attrs); + memset(p, 0, size); return p; } @@ -545,15 +457,15 @@ class GC /** * */ - void *realloc(void *p, size_t size, uint bits = 0) + void *realloc(void *p, size_t size, uint attrs = 0) { if (!thread_needLock()) { - return reallocNoSync(p, size, bits); + return reallocNoSync(p, size, attrs); } else synchronized (gcLock) { - return reallocNoSync(p, size, bits); + return reallocNoSync(p, size, attrs); } } @@ -561,24 +473,26 @@ class GC // // // - private void *reallocNoSync(void *p, size_t size, uint bits = 0) + private void *reallocNoSync(void *p, size_t size, uint attrs = 0) { if (!size) - { if (p) - { freeNoSync(p); + { + if (p) + { + freeNoSync(p); p = null; } } else if (!p) { - p = mallocNoSync(size, bits); + p = mallocNoSync(size, attrs); } else - { void *p2; + { + void *p2; size_t psize; - //debug(PRINTF) printf("GC::realloc(p = %x, size = %u)\n", p, size); - version (SENTINEL) + if (opts.options.sentinel) { sentinel_Invariant(p); psize = *sentinel_size(p); @@ -590,24 +504,23 @@ class GC if (pool) { - auto biti = cast(size_t)(p - pool.baseAddr) / 16; + auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; - if (bits) + if (attrs) { - gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); - gcx.setBits(pool, biti, bits); + gcx.clrAttr(pool, bit_i, BlkAttr.ALL_BITS); + gcx.setAttr(pool, bit_i, attrs); } else { - bits = gcx.getBits(pool, biti); + attrs = gcx.getAttr(pool, bit_i); } } } - p2 = mallocNoSync(size, bits); + p2 = mallocNoSync(size, attrs); if (psize < size) size = psize; - //debug(PRINTF) printf("\tcopying %d bytes\n",size); - .memcpy(p2, p, size); + cstring.memcpy(p2, p, size); p = p2; } } @@ -625,10 +538,12 @@ class GC auto pagenum = (p - pool.baseAddr) / PAGESIZE; if (newsz < psz) - { // Shrink in place + { + // Shrink in place synchronized (gcLock) { - debug (MEMSTOMP) .memset(p + size, 0xF2, psize - size); + if (opts.options.mem_stomp) + memset(p + size, 0xF2, psize - size); pool.freePages(pagenum + newsz, psz - newsz); } return p; @@ -642,8 +557,10 @@ class GC { if (i == pagenum + newsz) { - debug (MEMSTOMP) .memset(p + psize, 0xF0, size - psize); - .memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz); + if (opts.options.mem_stomp) + memset(p + psize, 0xF0, size - psize); + memset(pool.pagetable + pagenum + + psz, B_PAGEPLUS, newsz - psz); return p; } if (i == pool.npages) @@ -666,24 +583,23 @@ class GC if (pool) { - auto biti = cast(size_t)(p - pool.baseAddr) / 16; + auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; - if (bits) + if (attrs) { - gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); - gcx.setBits(pool, biti, bits); + gcx.clrAttr(pool, bit_i, BlkAttr.ALL_BITS); + gcx.setAttr(pool, bit_i, attrs); } else { - bits = gcx.getBits(pool, biti); + attrs = gcx.getAttr(pool, bit_i); } } } - p2 = mallocNoSync(size, bits); + p2 = mallocNoSync(size, attrs); if (psize < size) size = psize; - //debug(PRINTF) printf("\tcopying %d bytes\n",size); - .memcpy(p2, p, size); + cstring.memcpy(p2, p, size); p = p2; } } @@ -724,8 +640,7 @@ class GC } body { - //debug(PRINTF) printf("GC::extend(p = %x, minsize = %u, maxsize = %u)\n", p, minsize, maxsize); - version (SENTINEL) + if (opts.options.sentinel) { return 0; } @@ -747,15 +662,17 @@ class GC if (i == pool.npages) break; if (pool.pagetable[i] != B_FREE) - { if (sz < minsz) + { + if (sz < minsz) return 0; break; } } if (sz < minsz) return 0; - debug (MEMSTOMP) .memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize); - .memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz); + if (opts.options.mem_stomp) + memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize); + memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz); gcx.p_cache = null; gcx.size_cache = 0; return (psz + sz) * PAGESIZE; @@ -826,41 +743,43 @@ class GC Pool* pool; size_t pagenum; Bins bin; - size_t biti; + size_t bit_i; // Find which page it is in pool = gcx.findPool(p); if (!pool) // if not one of ours return; // ignore - sentinel_Invariant(p); - p = sentinel_sub(p); + if (opts.options.sentinel) { + sentinel_Invariant(p); + p = sentinel_sub(p); + } pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE; - biti = cast(size_t)(p - pool.baseAddr) / 16; - gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); + bit_i = cast(size_t)(p - pool.baseAddr) / 16; + gcx.clrAttr(pool, bit_i, BlkAttr.ALL_BITS); bin = cast(Bins)pool.pagetable[pagenum]; if (bin == B_PAGE) // if large alloc - { size_t npages; - size_t n; - + { // Free pages - npages = 1; - n = pagenum; + size_t npages = 1; + size_t n = pagenum; while (++n < pool.npages && pool.pagetable[n] == B_PAGEPLUS) npages++; - debug (MEMSTOMP) .memset(p, 0xF2, npages * PAGESIZE); + if (opts.options.mem_stomp) + memset(p, 0xF2, npages * PAGESIZE); pool.freePages(pagenum, npages); } else - { // Add to free list + { + // Add to free list List *list = cast(List*)p; - debug (MEMSTOMP) .memset(p, 0xF2, binsize[bin]); + if (opts.options.mem_stomp) + memset(p, 0xF2, binsize[bin]); list.next = gcx.bucket[bin]; gcx.bucket[bin] = list; } - gcx.log_free(sentinel_add(p)); } @@ -929,7 +848,7 @@ class GC { assert (p); - version (SENTINEL) + if (opts.options.sentinel) { p = sentinel_sub(p); size_t size = gcx.findSize(p); @@ -1031,7 +950,8 @@ class GC { assert(p); - sentinel_Invariant(p); + if (opts.options.sentinel) + sentinel_Invariant(p); debug (PTRCHECK) { Pool* pool; @@ -1039,7 +959,8 @@ class GC Bins bin; size_t size; - p = sentinel_sub(p); + if (opts.options.sentinel) + p = sentinel_sub(p); pool = gcx.findPool(p); assert(pool); pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE; @@ -1075,7 +996,6 @@ class GC //p = (void *)((uint *)p + 4); if (p > gcx.stackBottom) { - //debug(PRINTF) printf("setStackBottom(%x)\n", p); gcx.stackBottom = p; } } @@ -1084,7 +1004,6 @@ class GC //p = (void *)((uint *)p - 4); if (p < gcx.stackBottom) { - //debug(PRINTF) printf("setStackBottom(%x)\n", p); gcx.stackBottom = cast(char*)p; } } @@ -1103,11 +1022,13 @@ class GC if (!thread_needLock()) { - gcx.addRoot(p); + if (roots.append(p) is null) + onOutOfMemoryError(); } else synchronized (gcLock) { - gcx.addRoot(p); + if (roots.append(p) is null) + onOutOfMemoryError(); } } @@ -1122,14 +1043,16 @@ class GC return; } + bool r; if (!thread_needLock()) { - gcx.removeRoot(p); + r = roots.remove(p); } else synchronized (gcLock) { - gcx.removeRoot(p); + r = roots.remove(p); } + assert (r); } @@ -1143,16 +1066,16 @@ class GC return; } - //debug(PRINTF) printf("+GC.addRange(pbot = x%x, ptop = x%x)\n", pbot, ptop); if (!thread_needLock()) { - gcx.addRange(p, p + sz); + if (ranges.append(Range(p, p+sz)) is null) + onOutOfMemoryError(); } else synchronized (gcLock) { - gcx.addRange(p, p + sz); + if (ranges.append(Range(p, p+sz)) is null) + onOutOfMemoryError(); } - //debug(PRINTF) printf("-GC.addRange()\n"); } @@ -1166,14 +1089,16 @@ class GC return; } + bool r; if (!thread_needLock()) { - gcx.removeRange(p); + r = ranges.remove(Range(p, null)); } else synchronized (gcLock) { - gcx.removeRange(p); + r = ranges.remove(Range(p, null)); } + assert (r); } @@ -1182,7 +1107,6 @@ class GC */ void fullCollect() { - debug(PRINTF) printf("GC.fullCollect()\n"); if (!thread_needLock()) { @@ -1196,13 +1120,9 @@ class GC version (none) { GCStats stats; - getStats(stats); - debug(PRINTF) printf("poolsize = %x, usedsize = %x, freelistsize = %x\n", - stats.poolsize, stats.usedsize, stats.freelistsize); } - gcx.log_collect(); } @@ -1271,12 +1191,11 @@ class GC size_t n; size_t bsize = 0; - //debug(PRINTF) printf("getStats()\n"); - .memset(&stats, 0, GCStats.sizeof); - - for (n = 0; n < gcx.npools; n++) - { Pool *pool = gcx.pooltable[n]; + memset(&stats, 0, GCStats.sizeof); + for (n = 0; n < pools.length; n++) + { + Pool* pool = pools[n]; psize += pool.npages * PAGESIZE; for (size_t j = 0; j < pool.npages; j++) { @@ -1292,12 +1211,8 @@ class GC for (n = 0; n < B_PAGE; n++) { - //debug(PRINTF) printf("bin %d\n", n); for (List *list = gcx.bucket[n]; list; list = list.next) - { - //debug(PRINTF) printf("\tlist %x\n", list); flsize += binsize[n]; - } } usize = bsize - flsize; @@ -1344,7 +1259,7 @@ class GC // 1. to hide the reference from the GC // 2. the GC doesn't scan delegates added by rt_attachDisposeEvent // for references - auto wp = cast(WeakPointer*)(libc.malloc(WeakPointer.sizeof)); + auto wp = cast(WeakPointer*)(cstdlib.malloc(WeakPointer.sizeof)); if (!wp) onOutOfMemoryError(); wp.reference = r; @@ -1369,7 +1284,7 @@ class GC if (wp.reference) rt_detachDisposeEvent(wp.reference, &wp.ondestroy); }); - .free(wp); + cstdlib.free(wp); } } @@ -1397,7 +1312,8 @@ class GC /* ============================ Gcx =============================== */ enum -{ PAGESIZE = 4096, +{ + PAGESIZE = 4096, POOLSIZE = (4096*256), } @@ -1432,6 +1348,13 @@ struct Range { void *pbot; void *ptop; + int opCmp(in Range other) + { + if (pbot < other.pbot) + return -1; + else + return cast(int)(pbot > other.pbot); + } } @@ -1439,6 +1362,13 @@ const uint binsize[B_MAX] = [ 16,32,64,128,256,512,1024,2048,4096 ]; const uint notbinsize[B_MAX] = [ ~(16u-1),~(32u-1),~(64u-1),~(128u-1),~(256u-1), ~(512u-1),~(1024u-1),~(2048u-1),~(4096u-1) ]; +DynArray!(void*) roots; + +DynArray!(Range) ranges; + +DynArray!(Pool) pools; + + /* ============================ Gcx =============================== */ @@ -1448,14 +1378,6 @@ struct Gcx void *p_cache; size_t size_cache; - size_t nroots; - size_t rootdim; - void **roots; - - size_t nranges; - size_t rangedim; - Range *ranges; - uint noStack; // !=0 means don't scan stack uint log; // turn on logging uint anychanges; @@ -1466,44 +1388,19 @@ struct Gcx byte *minAddr; // min(baseAddr) byte *maxAddr; // max(topAddr) - size_t npools; - Pool **pooltable; - List *bucket[B_MAX]; // free list for each size void initialize() - { int dummy; - + { + int dummy; (cast(byte*)this)[0 .. Gcx.sizeof] = 0; stackBottom = cast(char*)&dummy; - log_init(); //printf("gcx = %p, self = %x\n", this, self); inited = 1; } - void Dtor() - { - inited = 0; - - for (size_t i = 0; i < npools; i++) - { Pool *pool = pooltable[i]; - - pool.Dtor(); - .free(pool); - } - if (pooltable) - .free(pooltable); - - if (roots) - .free(roots); - - if (ranges) - .free(ranges); - } - - void Invariant() { } @@ -1514,41 +1411,32 @@ struct Gcx //printf("Gcx.invariant(): this = %p\n", this); size_t i; - for (i = 0; i < npools; i++) - { Pool *pool = pooltable[i]; - + for (i = 0; i < pools.length; i++) + { + Pool* pool = pools[i]; pool.Invariant(); if (i == 0) { assert(minAddr == pool.baseAddr); } - if (i + 1 < npools) + if (i + 1 < pools.length) { - assert(pool.opCmp(pooltable[i + 1]) < 0); + assert(*pool < pools[i + 1]); } - else if (i + 1 == npools) + else if (i + 1 == pools.length) { assert(maxAddr == pool.topAddr); } } - if (roots) - { - assert(rootdim != 0); - assert(nroots <= rootdim); - } + roots.Invariant(); + ranges.Invariant(); - if (ranges) + for (i = 0; i < ranges.length; i++) { - assert(rangedim != 0); - assert(nranges <= rangedim); - - for (i = 0; i < nranges; i++) - { - assert(ranges[i].pbot); - assert(ranges[i].ptop); - assert(ranges[i].pbot <= ranges[i].ptop); - } + assert(ranges[i].pbot); + assert(ranges[i].ptop); + assert(ranges[i].pbot <= ranges[i].ptop); } for (i = 0; i < B_PAGE; i++) @@ -1561,122 +1449,26 @@ struct Gcx } - /** - * - */ - void addRoot(void *p) - { - if (nroots == rootdim) - { - size_t newdim = rootdim * 2 + 16; - void** newroots; - - newroots = cast(void**) .malloc(newdim * newroots[0].sizeof); - if (!newroots) - onOutOfMemoryError(); - if (roots) - { .memcpy(newroots, roots, nroots * newroots[0].sizeof); - .free(roots); - } - roots = newroots; - rootdim = newdim; - } - roots[nroots] = p; - nroots++; - } - - - /** - * - */ - void removeRoot(void *p) - { - for (size_t i = nroots; i--;) - { - if (roots[i] == p) - { - nroots--; - .memmove(roots + i, roots + i + 1, (nroots - i) * roots[0].sizeof); - return; - } - } - assert(0); - } - - - /** - * - */ - void addRange(void *pbot, void *ptop) - { - debug (PRINTF) printf("%x.Gcx::addRange(%x, %x), nranges = %d\n", this, - pbot, ptop, nranges); - if (nranges == rangedim) - { - size_t newdim = rangedim * 2 + 16; - Range *newranges; - - newranges = cast(Range*) .malloc(newdim * newranges[0].sizeof); - if (!newranges) - onOutOfMemoryError(); - if (ranges) - { .memcpy(newranges, ranges, nranges * newranges[0].sizeof); - .free(ranges); - } - ranges = newranges; - rangedim = newdim; - } - ranges[nranges].pbot = pbot; - ranges[nranges].ptop = ptop; - nranges++; - } - - - /** - * - */ - void removeRange(void *pbot) - { - debug (PRINTF) printf("%x.Gcx.removeRange(%x), nranges = %d\n", this, - pbot, nranges); - for (size_t i = nranges; i--;) - { - if (ranges[i].pbot == pbot) - { - nranges--; - .memmove(ranges + i, ranges + i + 1, (nranges - i) * ranges[0].sizeof); - return; - } - } - debug(PRINTF) printf("Wrong thread\n"); - - // This is a fatal error, but ignore it. - // The problem is that we can get a Close() call on a thread - // other than the one the range was allocated on. - //assert(zero); - } - - /** * Find Pool that pointer is in. * Return null if not in a Pool. - * Assume pooltable[] is sorted. + * Assume pools is sorted. */ Pool *findPool(void *p) { if (p >= minAddr && p < maxAddr) { - if (npools == 1) + if (pools.length == 1) { - return pooltable[0]; + return pools[0]; } - for (size_t i = 0; i < npools; i++) - { Pool *pool; - - pool = pooltable[i]; + for (size_t i = 0; i < pools.length; i++) + { + Pool* pool = pools[i]; if (p < pool.topAddr) - { if (pool.baseAddr <= p) + { + if (pool.baseAddr <= p) return pool; break; } @@ -1709,7 +1501,8 @@ struct Gcx else if (bin == B_PAGEPLUS) { do - { --pn, offset -= PAGESIZE; + { + --pn, offset -= PAGESIZE; } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); return pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1))); @@ -1786,8 +1579,10 @@ struct Gcx else if (bin == B_PAGEPLUS) { do - { --pn, offset -= PAGESIZE; - } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); + { + --pn, offset -= PAGESIZE; + } + while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); info.base = pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1))); @@ -1815,10 +1610,10 @@ struct Gcx } //////////////////////////////////////////////////////////////////// - // getBits + // getAttr //////////////////////////////////////////////////////////////////// - info.attr = getBits(pool, cast(size_t)(offset / 16)); + info.attr = getAttr(pool, cast(size_t)(offset / 16)); } return info; } @@ -1828,8 +1623,8 @@ struct Gcx * Compute bin for size. */ static Bins findBin(size_t size) - { Bins bin; - + { + Bins bin; if (size <= 256) { if (size <= 64) @@ -1872,7 +1667,7 @@ struct Gcx /** * Allocate a new pool of at least size bytes. - * Sort it into pooltable[]. + * Sort it into pools. * Mark all memory in the pool as B_FREE. * Return the actual number of bytes reserved or 0 on error. */ @@ -1896,27 +1691,22 @@ struct Gcx size_t pn; Pool* pool; - for (n = 0; n < npools; n++) + for (n = 0; n < pools.length; n++) { - pool = pooltable[n]; + pool = pools[n]; for (pn = 0; pn < pool.npages; pn++) { if (cast(Bins)pool.pagetable[pn] != B_FREE) break; } if (pn < pool.npages) - { - n++; continue; - } pool.Dtor(); - .free(pool); - .memmove(pooltable + n, - pooltable + n + 1, - (--npools - n) * (Pool*).sizeof); - minAddr = pooltable[0].baseAddr; - maxAddr = pooltable[npools - 1].topAddr; + pools.remove_at(n); + n--; } + minAddr = pools[0].baseAddr; + maxAddr = pools[pools.length - 1].topAddr; } @@ -1941,9 +1731,9 @@ struct Gcx // This code could use some refinement when repeatedly // allocating very large arrays. - for (n = 0; n < npools; n++) + for (n = 0; n < pools.length; n++) { - pool = pooltable[n]; + pool = pools[n]; pn = pool.allocPages(npages); if (pn != OPFAIL) goto L1; @@ -1954,13 +1744,15 @@ struct Gcx { case 0: if (disabled) - { state = 1; + { + state = 1; continue; } // Try collecting freedpages = fullcollectshell(); - if (freedpages >= npools * ((POOLSIZE / PAGESIZE) / 4)) - { state = 1; + if (freedpages >= pools.length * ((POOLSIZE / PAGESIZE) / 4)) + { + state = 1; continue; } // Release empty pools to prevent bloat @@ -1968,7 +1760,8 @@ struct Gcx // Allocate new pool pool = newPool(npages); if (!pool) - { state = 2; + { + state = 2; continue; } pn = pool.allocPages(npages); @@ -1994,11 +1787,11 @@ struct Gcx L1: pool.pagetable[pn] = B_PAGE; if (npages > 1) - .memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1); + memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1); p = pool.baseAddr + pn * PAGESIZE; - .memset(cast(char *)p + size, 0, npages * PAGESIZE - size); - debug (MEMSTOMP) .memset(p, 0xF1, size); - //debug(PRINTF) printf("\tp = %x\n", p); + memset(cast(char *)p + size, 0, npages * PAGESIZE - size); + if (opts.options.mem_stomp) + memset(p, 0xF1, size); return p; Lnomemory: @@ -2008,33 +1801,26 @@ struct Gcx /** * Allocate a new pool with at least npages in it. - * Sort it into pooltable[]. + * Sort it into pools. * Return null if failed. */ Pool *newPool(size_t npages) { - Pool* pool; - Pool** newpooltable; - size_t newnpools; - size_t i; - - //debug(PRINTF) printf("************Gcx::newPool(npages = %d)****************\n", npages); - // Minimum of POOLSIZE if (npages < POOLSIZE/PAGESIZE) npages = POOLSIZE/PAGESIZE; else if (npages > POOLSIZE/PAGESIZE) - { // Give us 150% of requested size, so there's room to extend + { + // Give us 150% of requested size, so there's room to extend auto n = npages + (npages >> 1); if (n < size_t.max/PAGESIZE) npages = n; } // Allocate successively larger pools up to 8 megs - if (npools) - { size_t n; - - n = npools; + if (pools.length) + { + size_t n = pools.length; if (n > 8) n = 8; // cap pool size at 8 megs n *= (POOLSIZE / PAGESIZE); @@ -2042,39 +1828,21 @@ struct Gcx npages = n; } - pool = cast(Pool *) .calloc(1, Pool.sizeof); - if (pool) + Pool p; + p.initialize(npages); + if (!p.baseAddr) { - pool.initialize(npages); - if (!pool.baseAddr) - goto Lerr; - - newnpools = npools + 1; - newpooltable = cast(Pool **) .realloc(pooltable, newnpools * (Pool *).sizeof); - if (!newpooltable) - goto Lerr; - - // Sort pool into newpooltable[] - for (i = 0; i < npools; i++) - { - if (pool.opCmp(newpooltable[i]) < 0) - break; - } - .memmove(newpooltable + i + 1, newpooltable + i, (npools - i) * (Pool *).sizeof); - newpooltable[i] = pool; - - pooltable = newpooltable; - npools = newnpools; + p.Dtor(); + return null; + } - minAddr = pooltable[0].baseAddr; - maxAddr = pooltable[npools - 1].topAddr; + Pool* pool = pools.insert_sorted(p); + if (pool) + { + minAddr = pools[0].baseAddr; + maxAddr = pools[pools.length - 1].topAddr; } return pool; - - Lerr: - pool.Dtor(); - .free(pool); - return null; } @@ -2091,10 +1859,9 @@ struct Gcx byte* p; byte* ptop; - //debug(PRINTF) printf("Gcx::allocPage(bin = %d)\n", bin); - for (n = 0; n < npools; n++) + for (n = 0; n < pools.length; n++) { - pool = pooltable[n]; + pool = pools[n]; pn = pool.allocPages(1); if (pn != OPFAIL) goto L1; @@ -2135,34 +1902,30 @@ struct Gcx Pool *pool; byte *p = cast(byte *)(*p1); - //if (log) debug(PRINTF) printf("\tmark %x\n", p); if (p >= minAddr && p < maxAddr) { if ((cast(size_t)p & ~(PAGESIZE-1)) == pcache) - continue; + continue; pool = findPool(p); if (pool) { size_t offset = cast(size_t)(p - pool.baseAddr); - size_t biti; + size_t bit_i; size_t pn = offset / PAGESIZE; Bins bin = cast(Bins)pool.pagetable[pn]; - //debug(PRINTF) printf("\t\tfound pool %x, base=%x, pn = %d, bin = %d, biti = x%x\n", pool, pool.baseAddr, pn, bin, biti); - // Adjust bit to be at start of allocated memory block if (bin <= B_PAGE) - { - biti = (offset & notbinsize[bin]) >> 4; - //debug(PRINTF) printf("\t\tbiti = x%x\n", biti); - } + bit_i = (offset & notbinsize[bin]) >> 4; else if (bin == B_PAGEPLUS) { do - { --pn; - } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); - biti = pn * (PAGESIZE / 16); + { + --pn; + } + while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); + bit_i = pn * (PAGESIZE / 16); } else { @@ -2173,17 +1936,14 @@ struct Gcx if (bin >= B_PAGE) // Cache B_PAGE and B_PAGEPLUS lookups pcache = cast(size_t)p & ~(PAGESIZE-1); - //debug(PRINTF) printf("\t\tmark(x%x) = %d\n", biti, pool.mark.test(biti)); - if (!pool.mark.test(biti)) + if (!pool.mark.test(bit_i)) { - //if (log) debug(PRINTF) printf("\t\tmarking %x\n", p); - pool.mark.set(biti); - if (!pool.noscan.test(biti)) + pool.mark.set(bit_i); + if (!pool.noscan.test(bit_i)) { - pool.scan.set(biti); + pool.scan.set(bit_i); changes = 1; } - log_parent(sentinel_add(pool.baseAddr + biti * 16), sentinel_add(pbot)); } } } @@ -2191,19 +1951,22 @@ struct Gcx anychanges |= changes; } - /** * Return number of full pages free'd. */ size_t fullcollectshell() { + stats.collection_started(); + scope (exit) + stats.collection_finished(); + // The purpose of the 'shell' is to ensure all the registers // get put on the stack so they'll be scanned void *sp; size_t result; version (GNU) { - __builtin_unwind_init(); + gcc.builtins.__builtin_unwind_init(); sp = & sp; } else version(LDC) @@ -2290,14 +2053,15 @@ struct Gcx debug(COLLECT_PRINTF) printf("Gcx.fullcollect()\n"); thread_suspendAll(); + stats.world_stopped(); p_cache = null; size_cache = 0; anychanges = 0; - for (n = 0; n < npools; n++) + for (n = 0; n < pools.length; n++) { - pool = pooltable[n]; + pool = pools[n]; pool.mark.zero(); pool.scan.zero(); pool.freebits.zero(); @@ -2314,9 +2078,9 @@ struct Gcx } } - for (n = 0; n < npools; n++) + for (n = 0; n < pools.length; n++) { - pool = pooltable[n]; + pool = pools[n]; pool.mark.copy(&pool.freebits); } @@ -2328,14 +2092,14 @@ struct Gcx thread_scanAll( &mark, stackTop ); } - // Scan roots[] + // Scan roots debug(COLLECT_PRINTF) printf("scan roots[]\n"); - mark(roots, roots + nroots); + mark(roots.ptr, roots.ptr + roots.length); - // Scan ranges[] + // Scan ranges debug(COLLECT_PRINTF) printf("scan ranges[]\n"); //log++; - for (n = 0; n < nranges; n++) + for (n = 0; n < ranges.length; n++) { debug(COLLECT_PRINTF) printf("\t%x .. %x\n", ranges[n].pbot, ranges[n].ptop); mark(ranges[n].pbot, ranges[n].ptop); @@ -2346,18 +2110,19 @@ struct Gcx while (anychanges) { anychanges = 0; - for (n = 0; n < npools; n++) + for (n = 0; n < pools.length; n++) { uint *bbase; uint *b; uint *btop; - pool = pooltable[n]; + pool = pools[n]; bbase = pool.scan.base(); btop = bbase + pool.scan.nwords; for (b = bbase; b < btop;) - { Bins bin; + { + Bins bin; size_t pn; size_t u; size_t bitm; @@ -2365,7 +2130,8 @@ struct Gcx bitm = *b; if (!bitm) - { b++; + { + b++; continue; } *b = 0; @@ -2395,7 +2161,8 @@ struct Gcx pn--; } u = 1; - while (pn + u < pool.npages && pool.pagetable[pn + u] == B_PAGEPLUS) + while (pn + u < pool.npages && + pool.pagetable[pn + u] == B_PAGEPLUS) u++; mark(o, o + u * PAGESIZE); } @@ -2405,103 +2172,112 @@ struct Gcx } thread_resumeAll(); + stats.world_started(); // Free up everything not marked debug(COLLECT_PRINTF) printf("\tfree'ing\n"); size_t freedpages = 0; size_t freed = 0; - for (n = 0; n < npools; n++) - { size_t pn; - uint* bbase; - - pool = pooltable[n]; - bbase = pool.mark.base(); + for (n = 0; n < pools.length; n++) + { + pool = pools[n]; + uint* bbase = pool.mark.base(); + size_t pn; for (pn = 0; pn < pool.npages; pn++, bbase += PAGESIZE / (32 * 16)) { Bins bin = cast(Bins)pool.pagetable[pn]; if (bin < B_PAGE) - { byte* p; - byte* ptop; - size_t biti; - size_t bitstride; - auto size = binsize[bin]; - - p = pool.baseAddr + pn * PAGESIZE; - ptop = p + PAGESIZE; - biti = pn * (PAGESIZE/16); - bitstride = size / 16; + { + auto size = binsize[bin]; + byte* p = pool.baseAddr + pn * PAGESIZE; + byte* ptop = p + PAGESIZE; + size_t bit_i = pn * (PAGESIZE/16); + size_t bit_stride = size / 16; version(none) // BUG: doesn't work because freebits() must also be cleared { // If free'd entire page - if (bbase[0] == 0 && bbase[1] == 0 && bbase[2] == 0 && bbase[3] == 0 && - bbase[4] == 0 && bbase[5] == 0 && bbase[6] == 0 && bbase[7] == 0) + if (bbase[0] == 0 && bbase[1] == 0 && bbase[2] == 0 && + bbase[3] == 0 && bbase[4] == 0 && bbase[5] == 0 && + bbase[6] == 0 && bbase[7] == 0) { - for (; p < ptop; p += size, biti += bitstride) + for (; p < ptop; p += size, bit_i += bit_stride) { - if (pool.finals.nbits && pool.finals.testClear(biti)) - rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/); - gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); + if (pool.finals.nbits && pool.finals.testClear(bit_i)) { + if (opts.options.sentinel) + rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/); + else + rt_finalize(cast(List *)p, false/*noStack > 0*/); + } + gcx.clrAttr(pool, bit_i, BlkAttr.ALL_BITS); List *list = cast(List *)p; - //debug(PRINTF) printf("\tcollecting %x\n", list); - log_free(sentinel_add(list)); - debug (MEMSTOMP) .memset(p, 0xF3, size); + if (opts.options.mem_stomp) + memset(p, 0xF3, size); } pool.pagetable[pn] = B_FREE; freed += PAGESIZE; - //debug(PRINTF) printf("freeing entire page %d\n", pn); continue; } } - for (; p < ptop; p += size, biti += bitstride) + for (; p < ptop; p += size, bit_i += bit_stride) { - if (!pool.mark.test(biti)) + if (!pool.mark.test(bit_i)) { - sentinel_Invariant(sentinel_add(p)); - - pool.freebits.set(biti); - if (pool.finals.nbits && pool.finals.testClear(biti)) - rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/); - clrBits(pool, biti, BlkAttr.ALL_BITS); + if (opts.options.sentinel) + sentinel_Invariant(sentinel_add(p)); + + pool.freebits.set(bit_i); + if (pool.finals.nbits && pool.finals.testClear(bit_i)) { + if (opts.options.sentinel) + rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/); + else + rt_finalize(cast(List *)p, false/*noStack > 0*/); + } + clrAttr(pool, bit_i, BlkAttr.ALL_BITS); List *list = cast(List *)p; - debug(PRINTF) printf("\tcollecting %x\n", list); - log_free(sentinel_add(list)); - debug (MEMSTOMP) .memset(p, 0xF3, size); + if (opts.options.mem_stomp) + memset(p, 0xF3, size); freed += size; } } } else if (bin == B_PAGE) - { size_t biti = pn * (PAGESIZE / 16); - - if (!pool.mark.test(biti)) - { byte *p = pool.baseAddr + pn * PAGESIZE; - - sentinel_Invariant(sentinel_add(p)); - if (pool.finals.nbits && pool.finals.testClear(biti)) - rt_finalize(sentinel_add(p), false/*noStack > 0*/); - clrBits(pool, biti, BlkAttr.ALL_BITS); + { + size_t bit_i = pn * (PAGESIZE / 16); + if (!pool.mark.test(bit_i)) + { + byte *p = pool.baseAddr + pn * PAGESIZE; + if (opts.options.sentinel) + sentinel_Invariant(sentinel_add(p)); + if (pool.finals.nbits && pool.finals.testClear(bit_i)) { + if (opts.options.sentinel) + rt_finalize(sentinel_add(p), false/*noStack > 0*/); + else + rt_finalize(p, false/*noStack > 0*/); + } + clrAttr(pool, bit_i, BlkAttr.ALL_BITS); debug(COLLECT_PRINTF) printf("\tcollecting big %x\n", p); - log_free(sentinel_add(p)); pool.pagetable[pn] = B_FREE; freedpages++; - debug (MEMSTOMP) .memset(p, 0xF3, PAGESIZE); + if (opts.options.mem_stomp) + memset(p, 0xF3, PAGESIZE); while (pn + 1 < pool.npages && pool.pagetable[pn + 1] == B_PAGEPLUS) { pn++; pool.pagetable[pn] = B_FREE; freedpages++; - debug (MEMSTOMP) - { p += PAGESIZE; - .memset(p, 0xF3, PAGESIZE); + if (opts.options.mem_stomp) + { + p += PAGESIZE; + memset(p, 0xF3, PAGESIZE); } } } @@ -2515,27 +2291,27 @@ struct Gcx // Free complete pages, rebuild free list debug(COLLECT_PRINTF) printf("\tfree complete pages\n"); size_t recoveredpages = 0; - for (n = 0; n < npools; n++) - { size_t pn; - - pool = pooltable[n]; - for (pn = 0; pn < pool.npages; pn++) + for (n = 0; n < pools.length; n++) + { + pool = pools[n]; + for (size_t pn = 0; pn < pool.npages; pn++) { Bins bin = cast(Bins)pool.pagetable[pn]; - size_t biti; + size_t bit_i; size_t u; if (bin < B_PAGE) { size_t size = binsize[bin]; - size_t bitstride = size / 16; - size_t bitbase = pn * (PAGESIZE / 16); - size_t bittop = bitbase + (PAGESIZE / 16); + size_t bit_stride = size / 16; + size_t bit_base = pn * (PAGESIZE / 16); + size_t bit_top = bit_base + (PAGESIZE / 16); byte* p; - biti = bitbase; - for (biti = bitbase; biti < bittop; biti += bitstride) - { if (!pool.freebits.test(biti)) + bit_i = bit_base; + for (; bit_i < bit_top; bit_i += bit_stride) + { + if (!pool.freebits.test(bit_i)) goto Lnotfree; } pool.pagetable[pn] = B_FREE; @@ -2545,12 +2321,13 @@ struct Gcx Lnotfree: p = pool.baseAddr + pn * PAGESIZE; for (u = 0; u < PAGESIZE; u += size) - { biti = bitbase + u / 16; - if (pool.freebits.test(biti)) - { List *list; - - list = cast(List *)(p + u); - if (list.next != bucket[bin]) // avoid unnecessary writes + { + bit_i = bit_base + u / 16; + if (pool.freebits.test(bit_i)) + { + List *list = cast(List *)(p + u); + // avoid unnecessary writes + if (list.next != bucket[bin]) list.next = bucket[bin]; bucket[bin] = list; } @@ -2560,7 +2337,7 @@ struct Gcx } debug(COLLECT_PRINTF) printf("recovered pages = %d\n", recoveredpages); - debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n", freed, freedpages, npools); + debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n", freed, freedpages, pools.length); return freedpages + recoveredpages; } @@ -2569,31 +2346,31 @@ struct Gcx /** * */ - uint getBits(Pool* pool, size_t biti) + uint getAttr(Pool* pool, size_t bit_i) in { assert( pool ); } body { - uint bits; + uint attrs; if (pool.finals.nbits && - pool.finals.test(biti)) - bits |= BlkAttr.FINALIZE; - if (pool.noscan.test(biti)) - bits |= BlkAttr.NO_SCAN; + pool.finals.test(bit_i)) + attrs |= BlkAttr.FINALIZE; + if (pool.noscan.test(bit_i)) + attrs |= BlkAttr.NO_SCAN; // if (pool.nomove.nbits && -// pool.nomove.test(biti)) -// bits |= BlkAttr.NO_MOVE; - return bits; +// pool.nomove.test(bit_i)) +// attrs |= BlkAttr.NO_MOVE; + return attrs; } /** * */ - void setBits(Pool* pool, size_t biti, uint mask) + void setAttr(Pool* pool, size_t bit_i, uint mask) in { assert( pool ); @@ -2604,17 +2381,17 @@ struct Gcx { if (!pool.finals.nbits) pool.finals.alloc(pool.mark.nbits); - pool.finals.set(biti); + pool.finals.set(bit_i); } if (mask & BlkAttr.NO_SCAN) { - pool.noscan.set(biti); + pool.noscan.set(bit_i); } // if (mask & BlkAttr.NO_MOVE) // { // if (!pool.nomove.nbits) // pool.nomove.alloc(pool.mark.nbits); -// pool.nomove.set(biti); +// pool.nomove.set(bit_i); // } } @@ -2622,7 +2399,7 @@ struct Gcx /** * */ - void clrBits(Pool* pool, size_t biti, uint mask) + void clrAttr(Pool* pool, size_t bit_i, uint mask) in { assert( pool ); @@ -2630,145 +2407,13 @@ struct Gcx body { if (mask & BlkAttr.FINALIZE && pool.finals.nbits) - pool.finals.clear(biti); + pool.finals.clear(bit_i); if (mask & BlkAttr.NO_SCAN) - pool.noscan.clear(biti); + pool.noscan.clear(bit_i); // if (mask & BlkAttr.NO_MOVE && pool.nomove.nbits) -// pool.nomove.clear(biti); +// pool.nomove.clear(bit_i); } - - /***** Leak Detector ******/ - - - debug (LOGGING) - { - LogArray current; - LogArray prev; - - - void log_init() - { - //debug(PRINTF) printf("+log_init()\n"); - current.reserve(1000); - prev.reserve(1000); - //debug(PRINTF) printf("-log_init()\n"); - } - - - void log_malloc(void *p, size_t size) - { - //debug(PRINTF) printf("+log_malloc(p = %x, size = %d)\n", p, size); - Log log; - - log.p = p; - log.size = size; - log.line = GC.line; - log.file = GC.file; - log.parent = null; - - GC.line = 0; - GC.file = null; - - current.push(log); - //debug(PRINTF) printf("-log_malloc()\n"); - } - - - void log_free(void *p) - { - //debug(PRINTF) printf("+log_free(%x)\n", p); - size_t i; - - i = current.find(p); - if (i == OPFAIL) - { - debug(PRINTF) printf("free'ing unallocated memory %x\n", p); - } - else - current.remove(i); - //debug(PRINTF) printf("-log_free()\n"); - } - - - void log_collect() - { - //debug(PRINTF) printf("+log_collect()\n"); - // Print everything in current that is not in prev - - debug(PRINTF) printf("New pointers this cycle: --------------------------------\n"); - size_t used = 0; - for (size_t i = 0; i < current.dim; i++) - { - size_t j; - - j = prev.find(current.data[i].p); - if (j == OPFAIL) - current.data[i].print(); - else - used++; - } - - debug(PRINTF) printf("All roots this cycle: --------------------------------\n"); - for (size_t i = 0; i < current.dim; i++) - { - void *p; - size_t j; - - p = current.data[i].p; - if (!findPool(current.data[i].parent)) - { - j = prev.find(current.data[i].p); - if (j == OPFAIL) - debug(PRINTF) printf("N"); - else - debug(PRINTF) printf(" ");; - current.data[i].print(); - } - } - - debug(PRINTF) printf("Used = %d-------------------------------------------------\n", used); - prev.copy(¤t); - - debug(PRINTF) printf("-log_collect()\n"); - } - - - void log_parent(void *p, void *parent) - { - //debug(PRINTF) printf("+log_parent()\n"); - size_t i; - - i = current.find(p); - if (i == OPFAIL) - { - debug(PRINTF) printf("parent'ing unallocated memory %x, parent = %x\n", p, parent); - Pool *pool; - pool = findPool(p); - assert(pool); - size_t offset = cast(size_t)(p - pool.baseAddr); - size_t biti; - size_t pn = offset / PAGESIZE; - Bins bin = cast(Bins)pool.pagetable[pn]; - biti = (offset & notbinsize[bin]); - debug(PRINTF) printf("\tbin = %d, offset = x%x, biti = x%x\n", bin, offset, biti); - } - else - { - current.data[i].parent = parent; - } - //debug(PRINTF) printf("-log_parent()\n"); - } - - } - else - { - void log_init() { } - void log_malloc(void *p, size_t size) { } - void log_free(void *p) { } - void log_collect() { } - void log_parent(void *p, void *parent) { } - } } @@ -2779,11 +2424,11 @@ struct Pool { byte* baseAddr; byte* topAddr; - GCBits mark; // entries already scanned, or should not be scanned - GCBits scan; // entries that need to be scanned - GCBits freebits; // entries that are on the free list - GCBits finals; // entries that need finalizer run on them - GCBits noscan; // entries that should not be scanned + GCBits mark; // entries already scanned, or should not be scanned + GCBits scan; // entries that need to be scanned + GCBits freebits; // entries that are on the free list + GCBits finals; // entries that need finalizer run on them + GCBits noscan; // entries that should not be scanned size_t npages; ubyte* pagetable; @@ -2791,21 +2436,15 @@ struct Pool void initialize(size_t npages) { - size_t poolsize; - - //debug(PRINTF) printf("Pool::Pool(%u)\n", npages); - poolsize = npages * PAGESIZE; + size_t poolsize = npages * PAGESIZE; assert(poolsize >= POOLSIZE); - baseAddr = cast(byte *)os_mem_map(poolsize); + baseAddr = cast(byte *) alloc.os_mem_map(poolsize); // Some of the code depends on page alignment of memory pools assert((cast(size_t)baseAddr & (PAGESIZE - 1)) == 0); if (!baseAddr) { - //debug(PRINTF) printf("GC fail: poolsize = x%x, errno = %d\n", poolsize, errno); - //debug(PRINTF) printf("message = '%s'\n", sys_errlist[errno]); - npages = 0; poolsize = 0; } @@ -2817,10 +2456,10 @@ struct Pool freebits.alloc(cast(size_t)poolsize / 16); noscan.alloc(cast(size_t)poolsize / 16); - pagetable = cast(ubyte*) .malloc(npages); + pagetable = cast(ubyte*) cstdlib.malloc(npages); if (!pagetable) onOutOfMemoryError(); - .memset(pagetable, B_FREE, npages); + memset(pagetable, B_FREE, npages); this.npages = npages; } @@ -2834,7 +2473,7 @@ struct Pool if (npages) { - result = os_mem_unmap(baseAddr, npages * PAGESIZE); + result = alloc.os_mem_unmap(baseAddr, npages * PAGESIZE); assert(result); npages = 0; } @@ -2842,8 +2481,9 @@ struct Pool baseAddr = null; topAddr = null; } + // See Gcx.Dtor() for the rationale of the null check. if (pagetable) - .free(pagetable); + cstdlib.free(pagetable); mark.Dtor(); scan.Dtor(); @@ -2872,8 +2512,8 @@ struct Pool } for (size_t i = 0; i < npages; i++) - { Bins bin = cast(Bins)pagetable[i]; - + { + Bins bin = cast(Bins)pagetable[i]; assert(bin < B_MAX); } } @@ -2888,16 +2528,13 @@ struct Pool size_t i; size_t n2; - //debug(PRINTF) printf("Pool::allocPages(n = %d)\n", n); n2 = n; for (i = 0; i < npages; i++) { if (pagetable[i] == B_FREE) { if (--n2 == 0) - { //debug(PRINTF) printf("\texisting pn = %d\n", i - n + 1); return i - n + 1; - } } else n2 = n; @@ -2911,19 +2548,19 @@ struct Pool */ void freePages(size_t pagenum, size_t npages) { - .memset(&pagetable[pagenum], B_FREE, npages); + memset(&pagetable[pagenum], B_FREE, npages); } /** - * Used for sorting pooltable[] + * Used for sorting pools */ - int opCmp(Pool *p2) + int opCmp(in Pool other) { - if (baseAddr < p2.baseAddr) + if (baseAddr < other.baseAddr) return -1; else - return cast(int)(baseAddr > p2.baseAddr); + return cast(int)(baseAddr > other.baseAddr); } } @@ -2931,68 +2568,41 @@ struct Pool /* ============================ SENTINEL =============================== */ -version (SENTINEL) -{ - const size_t SENTINEL_PRE = cast(size_t) 0xF4F4F4F4F4F4F4F4UL; // 32 or 64 bits - const ubyte SENTINEL_POST = 0xF5; // 8 bits - const uint SENTINEL_EXTRA = 2 * size_t.sizeof + 1; - +const size_t SENTINEL_PRE = cast(size_t) 0xF4F4F4F4F4F4F4F4UL; // 32 or 64 bits +const ubyte SENTINEL_POST = 0xF5; // 8 bits +const uint SENTINEL_EXTRA = 2 * size_t.sizeof + 1; - size_t* sentinel_size(void *p) { return &(cast(size_t *)p)[-2]; } - size_t* sentinel_pre(void *p) { return &(cast(size_t *)p)[-1]; } - ubyte* sentinel_post(void *p) { return &(cast(ubyte *)p)[*sentinel_size(p)]; } +size_t* sentinel_size(void *p) { return &(cast(size_t *)p)[-2]; } +size_t* sentinel_pre(void *p) { return &(cast(size_t *)p)[-1]; } +ubyte* sentinel_post(void *p) { return &(cast(ubyte *)p)[*sentinel_size(p)]; } - void sentinel_init(void *p, size_t size) - { - *sentinel_size(p) = size; - *sentinel_pre(p) = SENTINEL_PRE; - *sentinel_post(p) = SENTINEL_POST; - } - - void sentinel_Invariant(void *p) - { - assert(*sentinel_pre(p) == SENTINEL_PRE); - assert(*sentinel_post(p) == SENTINEL_POST); - } - - - void *sentinel_add(void *p) - { - return p + 2 * size_t.sizeof; - } - - - void *sentinel_sub(void *p) - { - return p - 2 * size_t.sizeof; - } -} -else +void sentinel_init(void *p, size_t size) { - const uint SENTINEL_EXTRA = 0; - - - void sentinel_init(void *p, size_t size) - { - } + *sentinel_size(p) = size; + *sentinel_pre(p) = SENTINEL_PRE; + *sentinel_post(p) = SENTINEL_POST; +} - void sentinel_Invariant(void *p) - { - } +void sentinel_Invariant(void *p) +{ + assert(*sentinel_pre(p) == SENTINEL_PRE); + assert(*sentinel_post(p) == SENTINEL_POST); +} - void *sentinel_add(void *p) - { - return p; - } +void *sentinel_add(void *p) +{ + return p + 2 * size_t.sizeof; +} - void *sentinel_sub(void *p) - { - return p; - } +void *sentinel_sub(void *p) +{ + return p - 2 * size_t.sizeof; } + +// vim: set et sw=4 sts=4 :