-
- 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 < 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)
- {
- 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)
- {
- for (; p < ptop; p += size, bit_i += bit_stride)
- {
- 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*/);
- }
- this.clrAttr(pool, bit_i, BlkAttr.ALL_BITS);
-
- List *list = cast(List *)p;
-
- if (opts.options.mem_stomp)
- memset(p, 0xF3, size);
- }
- pool.pagetable[pn] = B_FREE;
- freed += PAGESIZE;
- continue;
- }
- }
- for (; p < ptop; p += size, bit_i += bit_stride)
- {
- if (!pool.mark.test(bit_i))
- {
- 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;
-
- if (opts.options.mem_stomp)
- memset(p, 0xF3, size);
-
- freed += size;
- }
- }
- }
- else if (bin == B_PAGE)
- {
- 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);
- pool.pagetable[pn] = B_FREE;
- freedpages++;
- 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++;
-
- if (opts.options.mem_stomp)
- {
- p += PAGESIZE;
- memset(p, 0xF3, PAGESIZE);
- }
- }
- }
- }
- }
- }
-
- // Zero buckets
- bucket[] = null;
-
- // Free complete pages, rebuild free list
- debug(COLLECT_PRINTF) printf("\tfree complete pages\n");
- size_t recoveredpages = 0;
- 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 bit_i;
- size_t u;
-
- if (bin < B_PAGE)
- {
- size_t size = binsize[bin];
- size_t bit_stride = size / 16;
- size_t bit_base = pn * (PAGESIZE / 16);
- size_t bit_top = bit_base + (PAGESIZE / 16);
- byte* p;
-
- 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;
- recoveredpages++;
- continue;
-
- Lnotfree:
- p = pool.baseAddr + pn * PAGESIZE;
- for (u = 0; u < PAGESIZE; u += size)
- {
- 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;
- }
- }
- }
- }
- }
-
- 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, pools.length);
-
- return freedpages + recoveredpages;
- }
-
-
- /**
- *
- */
- uint getAttr(Pool* pool, size_t bit_i)
- in
- {
- assert( pool );
- }
- body
- {
- uint attrs;
-
- if (pool.finals.nbits &&
- 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(bit_i))
-// attrs |= BlkAttr.NO_MOVE;
- return attrs;
- }
-
-
- /**
- *
- */
- void setAttr(Pool* pool, size_t bit_i, uint mask)
- in
- {
- assert( pool );
- }
- body
- {
- if (mask & BlkAttr.FINALIZE)
- {
- if (!pool.finals.nbits)
- pool.finals.alloc(pool.mark.nbits);
- pool.finals.set(bit_i);
- }
- if (mask & BlkAttr.NO_SCAN)
- {
- pool.noscan.set(bit_i);
- }
-// if (mask & BlkAttr.NO_MOVE)
-// {
-// if (!pool.nomove.nbits)
-// pool.nomove.alloc(pool.mark.nbits);
-// pool.nomove.set(bit_i);
-// }
- }
-
-
- /**
- *
- */
- void clrAttr(Pool* pool, size_t bit_i, uint mask)
- in
- {
- assert( pool );
- }
- body
- {
- if (mask & BlkAttr.FINALIZE && pool.finals.nbits)
- pool.finals.clear(bit_i);
- if (mask & BlkAttr.NO_SCAN)
- pool.noscan.clear(bit_i);
-// if (mask & BlkAttr.NO_MOVE && pool.nomove.nbits)
-// pool.nomove.clear(bit_i);
- }
-
-
-
- void initialize()
- {
- int dummy;
- stackBottom = cast(char*)&dummy;
- opts.parse(cstdlib.getenv("D_GC_OPTS"));
- gcLock = GCLock.classinfo;
- inited = 1;
- setStackBottom(rt_stackBottom());
- stats = Stats(this);
- }
-
-
- /**
- *
- */
- void enable()
- {
- if (!thread_needLock())
- {
- assert(this.disabled > 0);
- this.disabled--;
- }
- else synchronized (gcLock)
- {
- assert(this.disabled > 0);
- this.disabled--;
- }
- }
-
-
- /**
- *
- */
- void disable()
- {
- if (!thread_needLock())
- {
- this.disabled++;
- }
- else synchronized (gcLock)
- {
- this.disabled++;
- }
- }
-
-
- /**
- *
- */
- uint getAttr(void* p)
- {
- if (!p)
- {
- return 0;
- }
-
- uint go()
- {
- Pool* pool = this.findPool(p);
- uint old_attrs = 0;
-
- if (pool)
- {
- auto bit_i = cast(size_t)(p - pool.baseAddr) / 16;
-
- old_attrs = this.getAttr(pool, bit_i);
- }
- return old_attrs;
- }
-
- if (!thread_needLock())
- {
- return go();
- }
- else synchronized (gcLock)
- {
- return go();
- }
- }
-
-
- /**
- *
- */
- uint setAttr(void* p, uint mask)
- {
- if (!p)
- {
- return 0;
- }
-
- uint go()
- {
- Pool* pool = this.findPool(p);
- uint old_attrs = 0;
-
- if (pool)
- {
- auto bit_i = cast(size_t)(p - pool.baseAddr) / 16;
-
- old_attrs = this.getAttr(pool, bit_i);
- this.setAttr(pool, bit_i, mask);
- }
- return old_attrs;
- }
-
- if (!thread_needLock())
- {
- return go();
- }
- else synchronized (gcLock)
- {
- return go();
- }
- }
-
-
- /**
- *
- */
- uint clrAttr(void* p, uint mask)
- {
- if (!p)
- {
- return 0;
- }
-
- uint go()
- {
- Pool* pool = this.findPool(p);
- uint old_attrs = 0;
-
- if (pool)
- {
- auto bit_i = cast(size_t)(p - pool.baseAddr) / 16;
-
- old_attrs = this.getAttr(pool, bit_i);
- this.clrAttr(pool, bit_i, mask);
- }
- return old_attrs;
- }
-
- if (!thread_needLock())
- {
- return go();
- }
- else synchronized (gcLock)
- {
- return go();
- }
- }
-
-
- /**
- *
- */
- void *malloc(size_t size, uint attrs, PointerMap ptrmap)
- {
- if (!size)
- {
- return null;
- }
-
- if (!thread_needLock())
- {
- return mallocNoSync(size, attrs, ptrmap.bits.ptr);
- }
- else synchronized (gcLock)
- {
- return mallocNoSync(size, attrs, ptrmap.bits.ptr);
- }
- }
-
-
- //
- //
- //
- private void *mallocNoSync(size_t size, uint attrs, size_t* pm_bitmask)
- {
- assert(size != 0);
-
- stats.malloc_started(size, attrs, pm_bitmask);
- scope (exit)
- stats.malloc_finished(p);
-
- void *p = null;
- Bins bin;
-
- if (opts.options.sentinel)
- size += SENTINEL_EXTRA;
-
- bool has_pm = has_pointermap(attrs);
- if (has_pm)
- size += size_t.sizeof;
-
- // Compute size bin
- // Cache previous binsize lookup - Dave Fladebo.
- static size_t lastsize = -1;
- static Bins lastbin;
- if (size == lastsize)
- bin = lastbin;
- else
- {
- bin = this.findBin(size);
- lastsize = size;
- lastbin = bin;
- }
-
- size_t capacity; // to figure out where to store the bitmask
- if (bin < B_PAGE)
- {
- p = this.bucket[bin];
- if (p is null)
- {
- if (!this.allocPage(bin) && !this.disabled) // try to find a new page
- {
- if (!thread_needLock())
- {
- /* Then we haven't locked it yet. Be sure
- * and lock for a collection, since a finalizer
- * may start a new thread.
- */
- synchronized (gcLock)
- {
- this.fullcollectshell();
- }
- }
- else if (!this.fullcollectshell()) // collect to find a new page
- {
- //this.newPool(1);
- }
- }
- if (!this.bucket[bin] && !this.allocPage(bin))
- {
- this.newPool(1); // allocate new pool to find a new page
- int result = this.allocPage(bin);
- if (!result)
- onOutOfMemoryError();
- }
- p = this.bucket[bin];
- }
- capacity = binsize[bin];
-
- // Return next item from free list
- this.bucket[bin] = (cast(List*)p).next;
- if (!(attrs & BlkAttr.NO_SCAN))
- memset(p + size, 0, capacity - size);
- if (opts.options.mem_stomp)
- memset(p, 0xF0, size);
- }
- else
- {
- p = this.bigAlloc(size);
- if (!p)
- onOutOfMemoryError();
- // Round the size up to the number of pages needed to store it
- size_t npages = (size + PAGESIZE - 1) / PAGESIZE;
- capacity = npages * PAGESIZE;
- }
-
- // Store the bit mask AFTER SENTINEL_POST
- // TODO: store it BEFORE, so the bitmask is protected too
- if (has_pm) {
- auto end_of_blk = cast(size_t**)(p + capacity - size_t.sizeof);
- *end_of_blk = pm_bitmask;
- size -= size_t.sizeof;
- }
-
- if (opts.options.sentinel) {
- size -= SENTINEL_EXTRA;
- p = sentinel_add(p);
- sentinel_init(p, size);
- }
-
- if (attrs)
- {
- Pool *pool = this.findPool(p);
- assert(pool);
-
- this.setAttr(pool, cast(size_t)(p - pool.baseAddr) / 16, attrs);
- }
- return p;
- }
-
-
- /**
- *
- */
- void *calloc(size_t size, uint attrs, PointerMap ptrmap)
- {
- if (!size)
- {
- return null;
- }
-
- if (!thread_needLock())
- {
- return callocNoSync(size, attrs, ptrmap.bits.ptr);
- }
- else synchronized (gcLock)
- {
- return callocNoSync(size, attrs, ptrmap.bits.ptr);
- }
- }
-
-
- //
- //
- //
- private void *callocNoSync(size_t size, uint attrs, size_t* pm_bitmask)
- {
- assert(size != 0);
-
- void *p = mallocNoSync(size, attrs, pm_bitmask);
- memset(p, 0, size);
- return p;
- }
-
-
- /**
- *
- */
- void *realloc(void *p, size_t size, uint attrs, PointerMap ptrmap)
- {
- if (!thread_needLock())
- {
- return reallocNoSync(p, size, attrs, ptrmap.bits.ptr);
- }
- else synchronized (gcLock)
- {
- return reallocNoSync(p, size, attrs, ptrmap.bits.ptr);
- }
- }
-
-
- //
- //
- //
- private void *reallocNoSync(void *p, size_t size, uint attrs,
- size_t* pm_bitmask)
- {
- if (!size)
- {
- if (p)
- {
- freeNoSync(p);
- p = null;
- }
- }
- else if (!p)
- {
- p = mallocNoSync(size, attrs, pm_bitmask);
- }
- else
- {
- Pool* pool = this.findPool(p);
- if (pool is null)
- return null;
-
- // Set or retrieve attributes as appropriate
- auto bit_i = cast(size_t)(p - pool.baseAddr) / 16;
- if (attrs) {
- this.clrAttr(pool, bit_i, BlkAttr.ALL_BITS);
- this.setAttr(pool, bit_i, attrs);
- }
- else
- attrs = this.getAttr(pool, bit_i);
-
- void* blk_base_addr = this.findBase(p);
- size_t blk_size = this.findSize(p);
- bool has_pm = has_pointermap(attrs);
- size_t pm_bitmask_size = 0;
- if (has_pm) {
- pm_bitmask_size = size_t.sizeof;
- // Retrieve pointer map bit mask if appropriate
- if (pm_bitmask is null) {
- auto end_of_blk = cast(size_t**)(blk_base_addr +
- blk_size - size_t.sizeof);
- pm_bitmask = *end_of_blk;
- }
- }
-
- if (opts.options.sentinel)
- {
- sentinel_Invariant(p);
- size_t sentinel_stored_size = *sentinel_size(p);
- if (sentinel_stored_size != size)
- {
- void* p2 = mallocNoSync(size, attrs, pm_bitmask);
- if (sentinel_stored_size < size)
- size = sentinel_stored_size;
- cstring.memcpy(p2, p, size);
- p = p2;
- }
- }
- else
- {
- size += pm_bitmask_size;
- if (blk_size >= PAGESIZE && size >= PAGESIZE)
- {
- auto psz = blk_size / PAGESIZE;
- auto newsz = (size + PAGESIZE - 1) / PAGESIZE;
- if (newsz == psz)
- return p;
-
- auto pagenum = (p - pool.baseAddr) / PAGESIZE;
-
- if (newsz < psz)
- {
- // Shrink in place
- synchronized (gcLock)
- {
- if (opts.options.mem_stomp)
- memset(p + size - pm_bitmask_size, 0xF2,
- blk_size - size - pm_bitmask_size);
- pool.freePages(pagenum + newsz, psz - newsz);
- }
- if (has_pm) {
- auto end_of_blk = cast(size_t**)(
- blk_base_addr + (PAGESIZE * newsz) -
- pm_bitmask_size);
- *end_of_blk = pm_bitmask;
- }
- return p;
- }
- else if (pagenum + newsz <= pool.npages)
- {
- // Attempt to expand in place
- synchronized (gcLock)
- {
- for (size_t i = pagenum + psz; 1;)
- {
- if (i == pagenum + newsz)
- {
- if (opts.options.mem_stomp)
- memset(p + blk_size - pm_bitmask_size,
- 0xF0, size - blk_size
- - pm_bitmask_size);
- memset(pool.pagetable + pagenum +
- psz, B_PAGEPLUS, newsz - psz);
- if (has_pm) {
- auto end_of_blk = cast(size_t**)(
- blk_base_addr +
- (PAGESIZE * newsz) -
- pm_bitmask_size);
- *end_of_blk = pm_bitmask;
- }
- return p;
- }
- if (i == pool.npages)
- {
- break;
- }
- if (pool.pagetable[i] != B_FREE)
- break;
- i++;
- }
- }
- }
- }
- // if new size is bigger or less than half
- if (blk_size < size || blk_size > size * 2)
- {
- size -= pm_bitmask_size;
- blk_size -= pm_bitmask_size;
- void* p2 = mallocNoSync(size, attrs, pm_bitmask);
- if (blk_size < size)
- size = blk_size;
- cstring.memcpy(p2, p, size);
- p = p2;
- }
- }
- }
- return p;
- }
-
-
- /**
- * Attempt to in-place enlarge the memory block pointed to by p by at least
- * minbytes beyond its current capacity, up to a maximum of maxsize. This
- * does not attempt to move the memory block (like realloc() does).
- *
- * Returns:
- * 0 if could not extend p,
- * total size of entire memory block if successful.
- */
- size_t extend(void* p, size_t minsize, size_t maxsize)
- {
- if (!thread_needLock())
- {
- return extendNoSync(p, minsize, maxsize);
- }
- else synchronized (gcLock)
- {
- return extendNoSync(p, minsize, maxsize);
- }
- }
-
-
- //
- //
- //
- private size_t extendNoSync(void* p, size_t minsize, size_t maxsize)
- in
- {
- assert( minsize <= maxsize );
- }
- body
- {
- if (opts.options.sentinel)
- return 0;
-
- Pool* pool = this.findPool(p);
- if (pool is null)
- return 0;
-
- // Retrieve attributes
- auto bit_i = cast(size_t)(p - pool.baseAddr) / 16;
- uint attrs = this.getAttr(pool, bit_i);
-
- void* blk_base_addr = this.findBase(p);
- size_t blk_size = this.findSize(p);
- bool has_pm = has_pointermap(attrs);
- size_t* pm_bitmask = null;
- size_t pm_bitmask_size = 0;
- if (has_pm) {
- pm_bitmask_size = size_t.sizeof;
- // Retrieve pointer map bit mask
- auto end_of_blk = cast(size_t**)(blk_base_addr +
- blk_size - size_t.sizeof);
- pm_bitmask = *end_of_blk;
-
- minsize += size_t.sizeof;
- maxsize += size_t.sizeof;
- }
-
- if (blk_size < PAGESIZE)
- return 0; // cannot extend buckets
-
- auto psz = blk_size / PAGESIZE;
- auto minsz = (minsize + PAGESIZE - 1) / PAGESIZE;
- auto maxsz = (maxsize + PAGESIZE - 1) / PAGESIZE;
-
- auto pagenum = (p - pool.baseAddr) / PAGESIZE;
-
- size_t sz;
- for (sz = 0; sz < maxsz; sz++)
- {
- auto i = pagenum + psz + sz;
- if (i == pool.npages)
- break;
- if (pool.pagetable[i] != B_FREE)
- {
- if (sz < minsz)
- return 0;
- break;
- }
- }
- if (sz < minsz)
- return 0;
-
- size_t new_size = (psz + sz) * PAGESIZE;
-
- if (opts.options.mem_stomp)
- memset(p + blk_size - pm_bitmask_size, 0xF0,
- new_size - blk_size - pm_bitmask_size);
- memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz);
- this.p_cache = null;
- this.size_cache = 0;
-
- if (has_pm) {
- new_size -= size_t.sizeof;
- auto end_of_blk = cast(size_t**)(blk_base_addr + new_size);
- *end_of_blk = pm_bitmask;
- }
- return new_size;
- }
-
-
- /**
- *
- */
- size_t reserve(size_t size)
- {
- if (!size)
- {
- return 0;
- }
-
- if (!thread_needLock())
- {
- return reserveNoSync(size);
- }
- else synchronized (gcLock)
- {
- return reserveNoSync(size);
- }
- }
-
-
- /**
- *
- */
- void free(void *p)
- {
- if (!p)
- {
- return;
- }
-
- if (!thread_needLock())
- {
- return freeNoSync(p);
- }
- else synchronized (gcLock)
- {
- return freeNoSync(p);
- }