]> git.llucax.com Git - software/dgc/cdgc.git/blobdiff - rt/gc/cdgc/gc.d
Improve variable names for block attributes
[software/dgc/cdgc.git] / rt / gc / cdgc / gc.d
index 1c9905524d5153926f3048045a55308ea027d85c..b9973b81a8079ed5bb33f4f0a7c476c153faadd8 100644 (file)
@@ -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(&current);
-
-            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 :