]> 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 3292622d8a08c944d9292b8adbc05a3ef6915748..b9973b81a8079ed5bb33f4f0a7c476c153faadd8 100644 (file)
@@ -31,8 +31,6 @@ module rt.gc.cdgc.gc;
 /************** Debugging ***************************/
 
 //debug = COLLECT_PRINTF;       // turn on printf's
 /************** Debugging ***************************/
 
 //debug = COLLECT_PRINTF;       // turn on printf's
-//debug = MEMSTOMP;             // stomp on memory
-//debug = SENTINEL;             // add underrun/overrrun protection
 //debug = PTRCHECK;             // more pointer checking
 //debug = PTRCHECK2;            // thorough but slow pointer checking
 
 //debug = PTRCHECK;             // more pointer checking
 //debug = PTRCHECK2;            // thorough but slow pointer checking
 
@@ -45,13 +43,30 @@ version = STACKGROWSDOWN;       // growing the stack means subtracting from the
 /***************************************************/
 
 import rt.gc.cdgc.bits: GCBits;
 /***************************************************/
 
 import rt.gc.cdgc.bits: GCBits;
-import rt.gc.cdgc.stats: GCStats;
-import alloc = rt.gc.cdgc.alloc;
+import rt.gc.cdgc.stats: GCStats, Stats;
 import rt.gc.cdgc.dynarray: DynArray;
 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;
 
 
 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)
 {
 
 version (GNU)
 {
@@ -62,7 +77,6 @@ version (GNU)
     static import gcc.builtins; // for __builtin_unwind_int
 }
 
     static import gcc.builtins; // for __builtin_unwind_int
 }
 
-
 struct BlkInfo
 {
     void*  base;
 struct BlkInfo
 {
     void*  base;
@@ -70,15 +84,16 @@ struct BlkInfo
     uint   attr;
 }
 
     uint   attr;
 }
 
+package enum BlkAttr : uint
+{
+    FINALIZE = 0b0000_0001,
+    NO_SCAN  = 0b0000_0010,
+    NO_MOVE  = 0b0000_0100,
+    ALL_BITS = 0b1111_1111
+}
+
 private
 {
 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();
 
     extern (C) void* rt_stackBottom();
     extern (C) void* rt_stackTop();
@@ -121,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.
 
 const uint GCVERSION = 1;       // increment every time we change interface
                                 // to GC.
 
+Stats stats;
+
 class GC
 {
     // For passing to debug code
 class GC
 {
     // For passing to debug code
@@ -135,12 +152,14 @@ class GC
 
     void initialize()
     {
 
     void initialize()
     {
+        opts.parse(cstdlib.getenv("D_GC_OPTS"));
         gcLock = GCLock.classinfo;
         gcx = cast(Gcx*) cstdlib.calloc(1, Gcx.sizeof);
         if (!gcx)
             onOutOfMemoryError();
         gcx.initialize();
         setStackBottom(rt_stackBottom());
         gcLock = GCLock.classinfo;
         gcx = cast(Gcx*) cstdlib.calloc(1, Gcx.sizeof);
         if (!gcx)
             onOutOfMemoryError();
         gcx.initialize();
         setStackBottom(rt_stackBottom());
+        stats = Stats(this);
     }
 
 
     }
 
 
@@ -191,15 +210,15 @@ class GC
         uint go()
         {
             Pool* pool = gcx.findPool(p);
         uint go()
         {
             Pool* pool = gcx.findPool(p);
-            uint  oldb = 0;
+            uint  old_attrs = 0;
 
             if (pool)
             {
 
             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())
         }
 
         if (!thread_needLock())
@@ -226,16 +245,16 @@ class GC
         uint go()
         {
             Pool* pool = gcx.findPool(p);
         uint go()
         {
             Pool* pool = gcx.findPool(p);
-            uint  oldb = 0;
+            uint  old_attrs = 0;
 
             if (pool)
             {
 
             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())
         }
 
         if (!thread_needLock())
@@ -262,16 +281,16 @@ class GC
         uint go()
         {
             Pool* pool = gcx.findPool(p);
         uint go()
         {
             Pool* pool = gcx.findPool(p);
-            uint  oldb = 0;
+            uint  old_attrs = 0;
 
             if (pool)
             {
 
             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())
         }
 
         if (!thread_needLock())
@@ -288,7 +307,7 @@ class GC
     /**
      *
      */
     /**
      *
      */
-    void *malloc(size_t size, uint bits = 0)
+    void *malloc(size_t size, uint attrs = 0)
     {
         if (!size)
         {
     {
         if (!size)
         {
@@ -297,11 +316,11 @@ class GC
 
         if (!thread_needLock())
         {
 
         if (!thread_needLock())
         {
-            return mallocNoSync(size, bits);
+            return mallocNoSync(size, attrs);
         }
         else synchronized (gcLock)
         {
         }
         else synchronized (gcLock)
         {
-            return mallocNoSync(size, bits);
+            return mallocNoSync(size, attrs);
         }
     }
 
         }
     }
 
@@ -309,16 +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);
 
     {
         assert(size != 0);
 
+        stats.malloc_started(size, attrs);
+        scope (exit)
+            stats.malloc_finished();
+
         void *p = null;
         Bins bin;
 
         assert(gcx);
 
         void *p = null;
         Bins bin;
 
         assert(gcx);
 
-        size += SENTINEL_EXTRA;
+        if (opts.options.sentinel)
+            size += SENTINEL_EXTRA;
 
         // Compute size bin
         // Cache previous binsize lookup - Dave Fladebo.
 
         // Compute size bin
         // Cache previous binsize lookup - Dave Fladebo.
@@ -368,9 +392,10 @@ class GC
 
             // Return next item from free list
             gcx.bucket[bin] = (cast(List*)p).next;
 
             // Return next item from free list
             gcx.bucket[bin] = (cast(List*)p).next;
-            if( !(bits & BlkAttr.NO_SCAN) )
-                cstring.memset(p + size, 0, binsize[bin] - size);
-            debug (MEMSTOMP) cstring.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
         {
         }
         else
         {
@@ -378,16 +403,18 @@ class GC
             if (!p)
                 onOutOfMemoryError();
         }
             if (!p)
                 onOutOfMemoryError();
         }
-        size -= SENTINEL_EXTRA;
-        p = sentinel_add(p);
-        sentinel_init(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);
 
         {
             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;
     }
         }
         return p;
     }
@@ -396,7 +423,7 @@ class GC
     /**
      *
      */
     /**
      *
      */
-    void *calloc(size_t size, uint bits = 0)
+    void *calloc(size_t size, uint attrs = 0)
     {
         if (!size)
         {
     {
         if (!size)
         {
@@ -405,11 +432,11 @@ class GC
 
         if (!thread_needLock())
         {
 
         if (!thread_needLock())
         {
-            return callocNoSync(size, bits);
+            return callocNoSync(size, attrs);
         }
         else synchronized (gcLock)
         {
         }
         else synchronized (gcLock)
         {
-            return callocNoSync(size, bits);
+            return callocNoSync(size, attrs);
         }
     }
 
         }
     }
 
@@ -417,12 +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);
 
     {
         assert(size != 0);
 
-        void *p = mallocNoSync(size, bits);
-        cstring.memset(p, 0, size);
+        void *p = mallocNoSync(size, attrs);
+        memset(p, 0, size);
         return p;
     }
 
         return p;
     }
 
@@ -430,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())
         {
     {
         if (!thread_needLock())
         {
-            return reallocNoSync(p, size, bits);
+            return reallocNoSync(p, size, attrs);
         }
         else synchronized (gcLock)
         {
         }
         else synchronized (gcLock)
         {
-            return reallocNoSync(p, size, bits);
+            return reallocNoSync(p, size, attrs);
         }
     }
 
         }
     }
 
@@ -446,7 +473,7 @@ 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 (!size)
         {
@@ -458,14 +485,14 @@ class GC
         }
         else if (!p)
         {
         }
         else if (!p)
         {
-            p = mallocNoSync(size, bits);
+            p = mallocNoSync(size, attrs);
         }
         else
         {
             void *p2;
             size_t psize;
 
         }
         else
         {
             void *p2;
             size_t psize;
 
-            version (SENTINEL)
+            if (opts.options.sentinel)
             {
                 sentinel_Invariant(p);
                 psize = *sentinel_size(p);
             {
                 sentinel_Invariant(p);
                 psize = *sentinel_size(p);
@@ -477,20 +504,20 @@ class GC
 
                         if (pool)
                         {
 
                         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
                             {
                             }
                             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;
                     cstring.memcpy(p2, p, size);
                     if (psize < size)
                         size = psize;
                     cstring.memcpy(p2, p, size);
@@ -515,8 +542,8 @@ class GC
                         // Shrink in place
                         synchronized (gcLock)
                         {
                         // Shrink in place
                         synchronized (gcLock)
                         {
-                            debug (MEMSTOMP)
-                                cstring.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;
                             pool.freePages(pagenum + newsz, psz - newsz);
                         }
                         return p;
@@ -530,10 +557,9 @@ class GC
                             {
                                 if (i == pagenum + newsz)
                                 {
                             {
                                 if (i == pagenum + newsz)
                                 {
-                                    debug (MEMSTOMP)
-                                        cstring.memset(p + psize, 0xF0,
-                                                size - psize);
-                                    cstring.memset(pool.pagetable + pagenum +
+                                    if (opts.options.mem_stomp)
+                                        memset(p + psize, 0xF0, size - psize);
+                                    memset(pool.pagetable + pagenum +
                                             psz, B_PAGEPLUS, newsz - psz);
                                     return p;
                                 }
                                             psz, B_PAGEPLUS, newsz - psz);
                                     return p;
                                 }
@@ -557,20 +583,20 @@ class GC
 
                         if (pool)
                         {
 
                         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
                             {
                             }
                             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;
                     cstring.memcpy(p2, p, size);
                     if (psize < size)
                         size = psize;
                     cstring.memcpy(p2, p, size);
@@ -614,7 +640,7 @@ class GC
     }
     body
     {
     }
     body
     {
-        version (SENTINEL)
+        if (opts.options.sentinel)
         {
             return 0;
         }
         {
             return 0;
         }
@@ -644,9 +670,9 @@ class GC
         }
         if (sz < minsz)
             return 0;
         }
         if (sz < minsz)
             return 0;
-        debug (MEMSTOMP)
-            cstring.memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize);
-        cstring.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;
         gcx.p_cache = null;
         gcx.size_cache = 0;
         return (psz + sz) * PAGESIZE;
@@ -717,17 +743,19 @@ class GC
         Pool*  pool;
         size_t pagenum;
         Bins   bin;
         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
 
         // 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;
         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
 
         bin = cast(Bins)pool.pagetable[pagenum];
         if (bin == B_PAGE)              // if large alloc
@@ -737,7 +765,8 @@ class GC
             size_t n = pagenum;
             while (++n < pool.npages && pool.pagetable[n] == B_PAGEPLUS)
                 npages++;
             size_t n = pagenum;
             while (++n < pool.npages && pool.pagetable[n] == B_PAGEPLUS)
                 npages++;
-            debug (MEMSTOMP) cstring.memset(p, 0xF2, npages * PAGESIZE);
+            if (opts.options.mem_stomp)
+                memset(p, 0xF2, npages * PAGESIZE);
             pool.freePages(pagenum, npages);
         }
         else
             pool.freePages(pagenum, npages);
         }
         else
@@ -745,7 +774,8 @@ class GC
             // Add to free list
             List *list = cast(List*)p;
 
             // Add to free list
             List *list = cast(List*)p;
 
-            debug (MEMSTOMP) cstring.memset(p, 0xF2, binsize[bin]);
+            if (opts.options.mem_stomp)
+                memset(p, 0xF2, binsize[bin]);
 
             list.next = gcx.bucket[bin];
             gcx.bucket[bin] = list;
 
             list.next = gcx.bucket[bin];
             gcx.bucket[bin] = list;
@@ -818,7 +848,7 @@ class GC
     {
         assert (p);
 
     {
         assert (p);
 
-        version (SENTINEL)
+        if (opts.options.sentinel)
         {
             p = sentinel_sub(p);
             size_t size = gcx.findSize(p);
         {
             p = sentinel_sub(p);
             size_t size = gcx.findSize(p);
@@ -920,7 +950,8 @@ class GC
     {
         assert(p);
 
     {
         assert(p);
 
-        sentinel_Invariant(p);
+        if (opts.options.sentinel)
+            sentinel_Invariant(p);
         debug (PTRCHECK)
         {
             Pool*  pool;
         debug (PTRCHECK)
         {
             Pool*  pool;
@@ -928,7 +959,8 @@ class GC
             Bins   bin;
             size_t size;
 
             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;
             pool = gcx.findPool(p);
             assert(pool);
             pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
@@ -1159,7 +1191,7 @@ class GC
         size_t n;
         size_t bsize = 0;
 
         size_t n;
         size_t bsize = 0;
 
-        cstring.memset(&stats, 0, GCStats.sizeof);
+        memset(&stats, 0, GCStats.sizeof);
 
         for (n = 0; n < pools.length; n++)
         {
 
         for (n = 0; n < pools.length; n++)
         {
@@ -1578,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;
     }
         }
         return info;
     }
@@ -1755,10 +1787,11 @@ struct Gcx
       L1:
         pool.pagetable[pn] = B_PAGE;
         if (npages > 1)
       L1:
         pool.pagetable[pn] = B_PAGE;
         if (npages > 1)
-            cstring.memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1);
+            memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1);
         p = pool.baseAddr + pn * PAGESIZE;
         p = pool.baseAddr + pn * PAGESIZE;
-        cstring.memset(cast(char *)p + size, 0, npages * PAGESIZE - size);
-        debug (MEMSTOMP) cstring.memset(p, 0xF1, size);
+        memset(cast(char *)p + size, 0, npages * PAGESIZE - size);
+        if (opts.options.mem_stomp)
+            memset(p, 0xF1, size);
         return p;
 
       Lnomemory:
         return p;
 
       Lnomemory:
@@ -1878,13 +1911,13 @@ struct Gcx
                 if (pool)
                 {
                     size_t offset = cast(size_t)(p - pool.baseAddr);
                 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];
 
                     // Adjust bit to be at start of allocated memory block
                     if (bin <= B_PAGE)
                     size_t pn = offset / PAGESIZE;
                     Bins   bin = cast(Bins)pool.pagetable[pn];
 
                     // Adjust bit to be at start of allocated memory block
                     if (bin <= B_PAGE)
-                        biti = (offset & notbinsize[bin]) >> 4;
+                        bit_i = (offset & notbinsize[bin]) >> 4;
                     else if (bin == B_PAGEPLUS)
                     {
                         do
                     else if (bin == B_PAGEPLUS)
                     {
                         do
@@ -1892,7 +1925,7 @@ struct Gcx
                             --pn;
                         }
                         while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
                             --pn;
                         }
                         while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
-                        biti = pn * (PAGESIZE / 16);
+                        bit_i = pn * (PAGESIZE / 16);
                     }
                     else
                     {
                     }
                     else
                     {
@@ -1903,12 +1936,12 @@ struct Gcx
                     if (bin >= B_PAGE) // Cache B_PAGE and B_PAGEPLUS lookups
                         pcache = cast(size_t)p & ~(PAGESIZE-1);
 
                     if (bin >= B_PAGE) // Cache B_PAGE and B_PAGEPLUS lookups
                         pcache = cast(size_t)p & ~(PAGESIZE-1);
 
-                    if (!pool.mark.test(biti))
+                    if (!pool.mark.test(bit_i))
                     {
                     {
-                        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;
                         }
                     }
                             changes = 1;
                         }
                     }
@@ -1918,12 +1951,15 @@ struct Gcx
         anychanges |= changes;
     }
 
         anychanges |= changes;
     }
 
-
     /**
      * Return number of full pages free'd.
      */
     size_t fullcollectshell()
     {
     /**
      * 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;
         // The purpose of the 'shell' is to ensure all the registers
         // get put on the stack so they'll be scanned
         void *sp;
@@ -2017,6 +2053,7 @@ struct Gcx
         debug(COLLECT_PRINTF) printf("Gcx.fullcollect()\n");
 
         thread_suspendAll();
         debug(COLLECT_PRINTF) printf("Gcx.fullcollect()\n");
 
         thread_suspendAll();
+        stats.world_stopped();
 
         p_cache = null;
         size_cache = 0;
 
         p_cache = null;
         size_cache = 0;
@@ -2124,7 +2161,8 @@ struct Gcx
                                     pn--;
                             }
                             u = 1;
                                     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);
                         }
                                 u++;
                             mark(o, o + u * PAGESIZE);
                         }
@@ -2134,6 +2172,7 @@ struct Gcx
         }
 
         thread_resumeAll();
         }
 
         thread_resumeAll();
+        stats.world_started();
 
         // Free up everything not marked
         debug(COLLECT_PRINTF) printf("\tfree'ing\n");
 
         // Free up everything not marked
         debug(COLLECT_PRINTF) printf("\tfree'ing\n");
@@ -2153,44 +2192,56 @@ struct Gcx
                     auto size = binsize[bin];
                     byte* p = pool.baseAddr + pn * PAGESIZE;
                     byte* ptop = p + PAGESIZE;
                     auto size = binsize[bin];
                     byte* p = pool.baseAddr + pn * PAGESIZE;
                     byte* ptop = p + PAGESIZE;
-                    size_t biti = pn * (PAGESIZE/16);
-                    size_t bitstride = size / 16;
+                    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
 
     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;
 
 
                             List *list = cast(List *)p;
 
-                            debug (MEMSTOMP) cstring.memset(p, 0xF3, size);
+                            if (opts.options.mem_stomp)
+                                memset(p, 0xF3, size);
                         }
                         pool.pagetable[pn] = B_FREE;
                         freed += PAGESIZE;
                         continue;
                     }
     }
                         }
                         pool.pagetable[pn] = B_FREE;
                         freed += PAGESIZE;
                         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;
 
 
                             List *list = cast(List *)p;
 
-                            debug (MEMSTOMP) cstring.memset(p, 0xF3, size);
+                            if (opts.options.mem_stomp)
+                                memset(p, 0xF3, size);
 
                             freed += size;
                         }
 
                             freed += size;
                         }
@@ -2198,29 +2249,35 @@ struct Gcx
                 }
                 else if (bin == B_PAGE)
                 {
                 }
                 else if (bin == B_PAGE)
                 {
-                    size_t biti = pn * (PAGESIZE / 16);
-                    if (!pool.mark.test(biti))
+                    size_t bit_i = pn * (PAGESIZE / 16);
+                    if (!pool.mark.test(bit_i))
                     {
                         byte *p = pool.baseAddr + pn * PAGESIZE;
                     {
                         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);
+                        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++;
 
                         debug(COLLECT_PRINTF) printf("\tcollecting big %x\n", p);
                         pool.pagetable[pn] = B_FREE;
                         freedpages++;
-                        debug (MEMSTOMP) cstring.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++;
 
                         while (pn + 1 < pool.npages && pool.pagetable[pn + 1] == B_PAGEPLUS)
                         {
                             pn++;
                             pool.pagetable[pn] = B_FREE;
                             freedpages++;
 
-                            debug (MEMSTOMP)
+                            if (opts.options.mem_stomp)
                             {
                                 p += PAGESIZE;
                             {
                                 p += PAGESIZE;
-                                cstring.memset(p, 0xF3, PAGESIZE);
+                                memset(p, 0xF3, PAGESIZE);
                             }
                         }
                     }
                             }
                         }
                     }
@@ -2240,21 +2297,21 @@ struct Gcx
             for (size_t pn = 0; pn < pool.npages; pn++)
             {
                 Bins   bin = cast(Bins)pool.pagetable[pn];
             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 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;
 
                     byte*  p;
 
-                    biti = bitbase;
-                    for (biti = bitbase; biti < bittop; biti += bitstride)
+                    bit_i = bit_base;
+                    for (; bit_i < bit_top; bit_i += bit_stride)
                     {
                     {
-                        if (!pool.freebits.test(biti))
+                        if (!pool.freebits.test(bit_i))
                             goto Lnotfree;
                     }
                     pool.pagetable[pn] = B_FREE;
                             goto Lnotfree;
                     }
                     pool.pagetable[pn] = B_FREE;
@@ -2265,11 +2322,12 @@ struct Gcx
                     p = pool.baseAddr + pn * PAGESIZE;
                     for (u = 0; u < PAGESIZE; u += size)
                     {
                     p = pool.baseAddr + pn * PAGESIZE;
                     for (u = 0; u < PAGESIZE; u += size)
                     {
-                        biti = bitbase + u / 16;
-                        if (pool.freebits.test(biti))
+                        bit_i = bit_base + u / 16;
+                        if (pool.freebits.test(bit_i))
                         {
                             List *list = cast(List *)(p + u);
                         {
                             List *list = cast(List *)(p + u);
-                            if (list.next != bucket[bin])       // avoid unnecessary writes
+                            // avoid unnecessary writes
+                            if (list.next != bucket[bin])
                                 list.next = bucket[bin];
                             bucket[bin] = list;
                         }
                                 list.next = bucket[bin];
                             bucket[bin] = list;
                         }
@@ -2288,31 +2346,31 @@ struct Gcx
     /**
      *
      */
     /**
      *
      */
-    uint getBits(Pool* pool, size_t biti)
+    uint getAttr(Pool* pool, size_t bit_i)
     in
     {
         assert( pool );
     }
     body
     {
     in
     {
         assert( pool );
     }
     body
     {
-        uint bits;
+        uint attrs;
 
         if (pool.finals.nbits &&
 
         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 &&
 //        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 );
     in
     {
         assert( pool );
@@ -2323,17 +2381,17 @@ struct Gcx
         {
             if (!pool.finals.nbits)
                 pool.finals.alloc(pool.mark.nbits);
         {
             if (!pool.finals.nbits)
                 pool.finals.alloc(pool.mark.nbits);
-            pool.finals.set(biti);
+            pool.finals.set(bit_i);
         }
         if (mask & BlkAttr.NO_SCAN)
         {
         }
         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);
         }
 //        if (mask & BlkAttr.NO_MOVE)
 //        {
 //            if (!pool.nomove.nbits)
 //                pool.nomove.alloc(pool.mark.nbits);
-//            pool.nomove.set(biti);
+//            pool.nomove.set(bit_i);
 //        }
     }
 
 //        }
     }
 
@@ -2341,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 );
     in
     {
         assert( pool );
@@ -2349,11 +2407,11 @@ struct Gcx
     body
     {
         if (mask & BlkAttr.FINALIZE && pool.finals.nbits)
     body
     {
         if (mask & BlkAttr.FINALIZE && pool.finals.nbits)
-            pool.finals.clear(biti);
+            pool.finals.clear(bit_i);
         if (mask & BlkAttr.NO_SCAN)
         if (mask & BlkAttr.NO_SCAN)
-            pool.noscan.clear(biti);
+            pool.noscan.clear(bit_i);
 //        if (mask & BlkAttr.NO_MOVE && pool.nomove.nbits)
 //        if (mask & BlkAttr.NO_MOVE && pool.nomove.nbits)
-//            pool.nomove.clear(biti);
+//            pool.nomove.clear(bit_i);
     }
 
 }
     }
 
 }
@@ -2401,7 +2459,7 @@ struct Pool
         pagetable = cast(ubyte*) cstdlib.malloc(npages);
         if (!pagetable)
             onOutOfMemoryError();
         pagetable = cast(ubyte*) cstdlib.malloc(npages);
         if (!pagetable)
             onOutOfMemoryError();
-        cstring.memset(pagetable, B_FREE, npages);
+        memset(pagetable, B_FREE, npages);
 
         this.npages = npages;
     }
 
         this.npages = npages;
     }
@@ -2490,7 +2548,7 @@ struct Pool
      */
     void freePages(size_t pagenum, size_t npages)
     {
      */
     void freePages(size_t pagenum, size_t npages)
     {
-        cstring.memset(&pagetable[pagenum], B_FREE, npages);
+        memset(&pagetable[pagenum], B_FREE, npages);
     }
 
 
     }
 
 
@@ -2510,69 +2568,40 @@ struct Pool
 /* ============================ SENTINEL =============================== */
 
 
 /* ============================ 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;
-
-
-    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)]; }
-
+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;
 
 
-    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);
-    }
 
 
+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_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;
 }
 
 
 }