Index: src/common/core/memory.d
===================================================================
--- src/common/core/memory.d	(revision 185)
+++ src/common/core/memory.d	(working copy)
@@ -13,6 +13,7 @@
  */
 module core.memory;
 
+__gshared size_t[3] conservativeBitMask = [cast(size_t) 3, 1, 0];
 
 private
 {
@@ -28,9 +29,9 @@
     extern (C) uint gc_setAttr( void* p, uint a );
     extern (C) uint gc_clrAttr( void* p, uint a );
 
-    extern (C) void*  gc_malloc( size_t sz, uint ba = 0 );
-    extern (C) void*  gc_calloc( size_t sz, uint ba = 0 );
-    extern (C) void*  gc_realloc( void* p, size_t sz, uint ba = 0 );
+    extern (C) void*  gc_malloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr);
+    extern (C) void*  gc_calloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr );
+    extern (C) void*  gc_realloc( void* p, size_t sz, uint ba = 0, size_t* bitMask = null);
     extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
     extern (C) size_t gc_reserve( size_t sz );
     extern (C) void   gc_free( void* p );
@@ -43,6 +44,7 @@
         void*  base;
         size_t size;
         uint   attr;
+
     }
 
     extern (C) BlkInfo_ gc_query( void* p );
@@ -201,6 +203,7 @@
      * Params:
      *  sz = The desired allocation size in bytes.
      *  ba = A bitmask of the attributes to set on this block.
+     *  bitMask = The pointer offset information for precise heap scanning.
      *
      * Returns:
      *  A reference to the allocated memory or null if insufficient memory
@@ -209,9 +212,10 @@
      * Throws:
      *  OutOfMemoryException on allocation failure.
      */
-    static void* malloc( size_t sz, uint ba = 0 )
+    static void* malloc( size_t sz, uint ba = 0,
+        const(size_t)* bitMask = conservativeBitMask.ptr )
     {
-        return gc_malloc( sz, ba );
+        return gc_malloc( sz, ba, cast(size_t*) bitMask );
     }
 
 
@@ -226,6 +230,7 @@
      * Params:
      *  sz = The desired allocation size in bytes.
      *  ba = A bitmask of the attributes to set on this block.
+     *  bitMask = The pointer offset information for precise heap scanning.
      *
      * Returns:
      *  A reference to the allocated memory or null if insufficient memory
@@ -234,9 +239,10 @@
      * Throws:
      *  OutOfMemoryException on allocation failure.
      */
-    static void* calloc( size_t sz, uint ba = 0 )
+    static void* calloc( size_t sz, uint ba = 0,
+        const(size_t)* bitMask = conservativeBitMask.ptr )
     {
-        return gc_calloc( sz, ba );
+        return gc_calloc( sz, ba, cast(size_t*) bitMask );
     }
 
 
@@ -258,12 +264,15 @@
      * reallocation is required.  If ba is not zero and p references the head
      * of a valid, known memory block then the bits in ba will replace those on
      * the current memory block and will also be set on the new block if a
-     * reallocation is required.
+     * reallocation is required.  Similarly, if bitMask is non-null, then
+     * the bitmask for the current block will propagated to the new block.
+     * Otherwise, the bitmask provided will be propagated to the old block.
      *
      * Params:
      *  p  = A pointer to the root of a valid memory block or to null.
      *  sz = The desired allocation size in bytes.
      *  ba = A bitmask of the attributes to set on this block.
+     *  bitMask = The pointer offset information for precise heap scanning.
      *
      * Returns:
      *  A reference to the allocated memory on success or null if sz is
@@ -272,9 +281,10 @@
      * Throws:
      *  OutOfMemoryException on allocation failure.
      */
-    static void* realloc( void* p, size_t sz, uint ba = 0 )
+    static void* realloc( void* p, size_t sz, uint ba = 0,
+        size_t* bitMask = null )
     {
-        return gc_realloc( p, sz, ba );
+        return gc_realloc( p, sz, ba, cast(size_t*) bitMask );
     }
 
 
Index: src/compiler/dmd/rt/aaA.d
===================================================================
--- src/compiler/dmd/rt/aaA.d	(revision 185)
+++ src/compiler/dmd/rt/aaA.d	(working copy)
@@ -26,8 +26,9 @@
         ALL_BITS = 0b1111_1111
     }
 
-    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
-    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
+    __gshared size_t[3] conservativeBitMask = [3, 1, 0];
+    extern (C) void* gc_malloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr);
+    extern (C) void* gc_calloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr);
     extern (C) void  gc_free( void* p );
 }
 
Index: src/compiler/dmd/rt/adi.d
===================================================================
--- src/compiler/dmd/rt/adi.d	(revision 185)
+++ src/compiler/dmd/rt/adi.d	(working copy)
@@ -29,8 +29,9 @@
         ALL_BITS = 0b1111_1111
     }
 
-    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
-    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
+    __gshared size_t[3] conservativeBitMask = [3, 1, 0];
+    extern (C) void* gc_malloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr );
+    extern (C) void* gc_calloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr );
     extern (C) void  gc_free( void* p );
 }
 
Index: src/compiler/dmd/rt/lifetime.d
===================================================================
--- src/compiler/dmd/rt/lifetime.d	(revision 185)
+++ src/compiler/dmd/rt/lifetime.d	(working copy)
@@ -21,7 +21,8 @@
     import core.stdc.stdlib;
     import core.stdc.string;
     import core.stdc.stdarg;
-    debug(PRINTF) import core.stdc.stdio;
+    debug(PRINTF) import core.stdc.stdio;
+    __gshared size_t[3] conservativeBitMask = [3, 1, 0];
 }
 
 
@@ -46,8 +47,8 @@
     extern (C) uint gc_setAttr( void* p, uint a );
     extern (C) uint gc_clrAttr( void* p, uint a );
 
-    extern (C) void*  gc_malloc( size_t sz, uint ba = 0 );
-    extern (C) void*  gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) void*  gc_malloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr );
+    extern (C) void*  gc_calloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr );
     extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
     extern (C) void   gc_free( void* p );
 
Index: src/gc/basic/gc.d
===================================================================
--- src/gc/basic/gc.d	(revision 185)
+++ src/gc/basic/gc.d	(working copy)
@@ -40,9 +40,9 @@
         extern (C) uint function(void*, uint) gc_setAttr;
         extern (C) uint function(void*, uint) gc_clrAttr;
 
-        extern (C) void*  function(size_t, uint) gc_malloc;
-        extern (C) void*  function(size_t, uint) gc_calloc;
-        extern (C) void*  function(void*, size_t, uint ba) gc_realloc;
+        extern (C) void*  function(size_t, uint, size_t*) gc_malloc;
+        extern (C) void*  function(size_t, uint, size_t*) gc_calloc;
+        extern (C) void*  function(void*, size_t, uint ba, size_t*) gc_realloc;
         extern (C) size_t function(void*, size_t, size_t) gc_extend;
         extern (C) size_t function(size_t) gc_reserve;
         extern (C) void   function(void*) gc_free;
@@ -180,25 +180,25 @@
     return proxy.gc_clrAttr( p, a );
 }
 
-extern (C) void* gc_malloc( size_t sz, uint ba = 0 )
+extern (C) void* gc_malloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr)
 {
     if( proxy is null )
-        return _gc.malloc( sz, ba );
-    return proxy.gc_malloc( sz, ba );
+        return _gc.malloc( sz, ba, bitMask );
+    return proxy.gc_malloc( sz, ba, bitMask );
 }
 
-extern (C) void* gc_calloc( size_t sz, uint ba = 0 )
+extern (C) void* gc_calloc( size_t sz, uint ba = 0, size_t* bitMask = conservativeBitMask.ptr)
 {
     if( proxy is null )
-        return _gc.calloc( sz, ba );
-    return proxy.gc_calloc( sz, ba );
+        return _gc.calloc( sz, ba, bitMask );
+    return proxy.gc_calloc( sz, ba, bitMask );
 }
 
-extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 )
+extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0, size_t* bitMask = null)
 {
     if( proxy is null )
-        return _gc.realloc( p, sz, ba );
-    return proxy.gc_realloc( p, sz, ba );
+        return _gc.realloc( p, sz, ba, bitMask );
+    return proxy.gc_realloc( p, sz, ba, bitMask );
 }
 
 extern (C) size_t gc_extend( void* p, size_t mx, size_t sz )
Index: src/gc/basic/gcx.d
===================================================================
--- src/gc/basic/gcx.d	(revision 185)
+++ src/gc/basic/gcx.d	(working copy)
@@ -18,6 +18,7 @@
 
 //debug = PRINTF;               // turn on printf's
 //debug = COLLECT_PRINTF;       // turn on printf's
+//debug = COLLECT_LOOP_PRINTF;   // turn on really long printf's inside the collect loop.
 //debug = THREADINVARIANT;      // check thread integrity
 //debug = LOGGING;              // log allocations / frees
 //debug = MEMSTOMP;             // stomp on memory
@@ -45,6 +46,9 @@
 debug (COLLECT_PRINTF) import core.stdc.stdio : printf;
 debug private import core.stdc.stdio;
 
+// Default bit mask for conservative scanning.
+__gshared size_t[3] conservativeBitMask = [3, 1, 0];
+
 private
 {
     enum USE_CACHE = true;
@@ -190,7 +194,6 @@
     }
 }
 
-
 /* ============================ GC =============================== */
 
 
@@ -393,7 +396,7 @@
     /**
      *
      */
-    void *malloc(size_t size, uint bits = 0)
+    void *malloc(size_t size, uint bits, size_t* bitMask)
     {
         if (!size)
         {
@@ -405,7 +408,7 @@
         // when allocating.
         synchronized (gcLock)
         {
-            return mallocNoSync(size, bits);
+            return mallocNoSync(size, bits, bitMask);
         }
     }
 
@@ -413,19 +416,23 @@
     //
     //
     //
-    private void *mallocNoSync(size_t size, uint bits = 0)
+    private void *mallocNoSync(size_t size, uint bits, size_t* bitMask)
     {
         assert(size != 0);
 
         void *p = null;
         Bins bin;
 
-        //debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p)\n", size, gcx);
+        debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p, bitMask = %p)\n", size, gcx, bitMask);
         assert(gcx);
         //debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self());
 
         size += SENTINEL_EXTRA;
 
+        bool hasBitMask = !(bits & BlkAttr.NO_SCAN);
+        size_t bitMaskSize = (size_t*).sizeof * hasBitMask;
+        size += bitMaskSize;
+
         // Compute size bin
         // Cache previous binsize lookup - Dave Fladebo.
         __gshared size_t lastsize = -1;
@@ -439,6 +446,7 @@
             lastbin = bin;
         }
 
+        size_t capacity;  // To figure out where to store the bitmask.
         if (bin < B_PAGE)
         {
             int  state     = gcx.disabled ? 1 : 0;
@@ -467,6 +475,7 @@
                 }
             }
             p = gcx.bucket[bin];
+            capacity = binSize(bin);
 
             // Return next item from free list
             gcx.bucket[bin] = (cast(List*)p).next;
@@ -480,7 +489,18 @@
             p = gcx.bigAlloc(size);
             if (!p)
                 onOutOfMemoryError();
+            size_t npages = (size + PAGESIZE - 1) / PAGESIZE;
+            capacity = npages * PAGESIZE;
         }
+
+        // Store the bit mask AFTER SENTINEL_POST.
+        if(hasBitMask) {
+            size_t** endOfBlock = cast(size_t**)
+                (p + capacity - bitMaskSize);
+            *endOfBlock = bitMask;
+            size -= bitMaskSize;
+        }
+
         size -= SENTINEL_EXTRA;
         p = sentinel_add(p);
         sentinel_init(p, size);
@@ -493,6 +513,7 @@
 
             gcx.setBits(pool, cast(size_t)(p - pool.baseAddr) / 16, bits);
         }
+        debug(PRINTF) printf("Done malloc.  Ptr:  %p  Bitmask:  %p\n", p, bitMask);
         return p;
     }
 
@@ -500,7 +521,7 @@
     /**
      *
      */
-    void *calloc(size_t size, uint bits = 0)
+    void *calloc(size_t size, uint bits, size_t* bitMask)
     {
         if (!size)
         {
@@ -512,7 +533,7 @@
         // when allocating.
         synchronized (gcLock)
         {
-            return callocNoSync(size, bits);
+            return callocNoSync(size, bits, bitMask);
         }
     }
 
@@ -520,12 +541,12 @@
     //
     //
     //
-    private void *callocNoSync(size_t size, uint bits = 0)
+    private void *callocNoSync(size_t size, uint bits, size_t* bitMask)
     {
         assert(size != 0);
 
         //debug(PRINTF) printf("calloc: %x len %d\n", p, len);
-        void *p = mallocNoSync(size, bits);
+        void *p = mallocNoSync(size, bits, bitMask);
         memset(p, 0, size);
         return p;
     }
@@ -534,151 +555,186 @@
     /**
      *
      */
-    void *realloc(void *p, size_t size, uint bits = 0)
+    void *realloc(void *p, size_t size, uint bits, size_t* bitMask)
     {
         // Since a finalizer could launch a new thread, we always need to lock
         // when collecting.  The safest way to do this is to simply always lock
         // when allocating.
         synchronized (gcLock)
         {
-            return reallocNoSync(p, size, bits);
+            return reallocNoSync(p, size, bits, bitMask);
         }
     }
 
+    // Boilerplate code dealing with bitmasks, used in both realloc() and
+    // extend().
+    enum string bitMaskMixin = q{
+        // Finding the pool is expensive so do it once and ONLY
+        // once, then keep recycling.
+        Pool* pool = gcx.findPool(p);
+        size_t psize = gcx.findSize(p, pool);        // find allocated size
+        void* baseAddr = gcx.findBase(p, pool);
 
+        if(pool !is null) {
+            auto biti = cast(size_t)(p - pool.baseAddr) / 16;
+
+            if(bits) {
+                gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
+                gcx.setBits(pool, biti, bits);
+            } else {
+                bits = gcx.getBits(pool, biti);
+            }
+        }
+
+        bool hasBitMask = !(bits & BlkAttr.NO_SCAN);
+
+        void setBitMask() {
+            if(baseAddr is null && !hasBitMask) {
+                // Use the already-declared bit mask.
+                return;
+            }
+
+            // Don't get the bitmask from the block if the user specified
+            // a new one.
+            if(bitMask !is null) {
+                return;
+            }
+
+            size_t** bitMaskPtr = cast(size_t**)
+                (baseAddr + psize - (size_t*).sizeof);
+            bitMask = *bitMaskPtr;
+        }
+
+        setBitMask();
+        size_t bitMaskSize = (hasBitMask) ? (size_t*).sizeof : 0;
+    };
+
+
     //
     //
     //
-    private void *reallocNoSync(void *p, size_t size, uint bits = 0)
+    private void *reallocNoSync(void *p, size_t size, uint bits,
+        size_t* bitMask)
     {
         if (!size)
         {   if (p)
             {   freeNoSync(p);
-                p = null;
+                return null;
             }
         }
         else if (!p)
         {
-            p = mallocNoSync(size, bits);
+            if(bitMask is null) {
+                // Default to conservative mask.
+                return mallocNoSync(size, bits, conservativeBitMask.ptr);
+            }
+            return mallocNoSync(size, bits, bitMask);
         }
-        else
-        {   void *p2;
-            size_t psize;
 
-            //debug(PRINTF) printf("GC::realloc(p = %x, size = %u)\n", p, size);
-            version (SENTINEL)
+        mixin(bitMaskMixin);
+        void *p2;
+
+        if(hasBitMask) {  // Add in stuff for bit mask.
+            size += (size_t*).sizeof;
+        }
+
+        debug(PRINTF) {
+            printf("GC::realloc(p = %x, size = %u)\n", p, size);
+            scope(exit) printf("Done realloc.");
+        }
+
+        version (SENTINEL)
+        {
+            sentinel_Invariant(p);
+            psize = *sentinel_size(p);
+            if (psize != size)
             {
-                sentinel_Invariant(p);
-                psize = *sentinel_size(p);
-                if (psize != size)
-                {
-                    if (psize)
-                    {
-                        Pool *pool = gcx.findPool(p);
+                p2 = mallocNoSync(size, bits, bitMask);
 
-                        if (pool)
-                        {
-                            auto biti = cast(size_t)(p - pool.baseAddr) / 16;
-
-                            if (bits)
-                            {
-                                gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
-                                gcx.setBits(pool, biti, bits);
-                            }
-                            else
-                            {
-                                bits = gcx.getBits(pool, biti);
-                            }
-                        }
-                    }
-                    p2 = mallocNoSync(size, bits);
-                    if (psize < size)
-                        size = psize;
-                    //debug(PRINTF) printf("\tcopying %d bytes\n",size);
-                    memcpy(p2, p, size);
-                    p = p2;
-                }
+                size -= bitMaskSize;
+                psize -= bitMaskSize;
+                if (psize < size)
+                    size = psize;
+                //debug(PRINTF) printf("\tcopying %d bytes\n",size);
+                memcpy(p2, p, size);
+                p = p2;
             }
-            else
+        }
+        else
+        {
+            if (psize >= PAGESIZE && size >= PAGESIZE)
             {
-                psize = gcx.findSize(p);        // find allocated size
-                if (psize >= PAGESIZE && size >= PAGESIZE)
-                {
-                    auto psz = psize / PAGESIZE;
-                    auto newsz = (size + PAGESIZE - 1) / PAGESIZE;
-                    if (newsz == psz)
-                        return p;
+                auto psz = psize / PAGESIZE;
+                auto newsz = (size + PAGESIZE - 1) / PAGESIZE;
+                if (newsz == psz)
+                    return p;
 
-                    auto pool = gcx.findPool(p);
-                    auto pagenum = (p - pool.baseAddr) / PAGESIZE;
+                auto pagenum = (p - pool.baseAddr) / PAGESIZE;
 
-                    if (newsz < psz)
-                    {   // Shrink in place
-                        synchronized (gcLock)
-                        {
-                            debug (MEMSTOMP) memset(p + size, 0xF2, psize - size);
-                            pool.freePages(pagenum + newsz, psz - newsz);
-                        }
-                        return p;
-                    }
-                    else if (pagenum + newsz <= pool.npages)
+                if (newsz < psz)
+                {   // Shrink in place
+                    synchronized (gcLock)
                     {
-                        // Attempt to expand in place
-                        synchronized (gcLock)
-                        {
-                            for (size_t i = pagenum + psz; 1;)
-                            {
-                                if (i == pagenum + newsz)
-                                {
-                                    debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize);
-                                    memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz);
-                                    return p;
-                                }
-                                if (i == pool.ncommitted)
-                                {
-                                    auto u = pool.extendPages(pagenum + newsz - pool.ncommitted);
-                                    if (u == OPFAIL)
-                                        break;
-                                    i = pagenum + newsz;
-                                    continue;
-                                }
-                                if (pool.pagetable[i] != B_FREE)
-                                    break;
-                                i++;
-                            }
-                        }
+                        debug (MEMSTOMP) memset(p + size, 0xF2, psize - size);
+                        pool.freePages(pagenum + newsz, psz - newsz);
                     }
+
+                    if(hasBitMask) {
+                        size_t** newBitmaskPtr = cast(size_t**) (baseAddr +
+                            (PAGESIZE * newsz) - (size_t*).sizeof);
+                        *newBitmaskPtr = bitMask;
+                    }
+
+                    return p;
                 }
-                if (psize < size ||             // if new size is bigger
-                    psize > size * 2)           // or less than half
+                else if (pagenum + newsz <= pool.npages)
                 {
-                    if (psize)
+                    // Attempt to expand in place
+                    synchronized (gcLock)
                     {
-                        Pool *pool = gcx.findPool(p);
-
-                        if (pool)
+                        for (size_t i = pagenum + psz; 1;)
                         {
-                            auto biti = cast(size_t)(p - pool.baseAddr) / 16;
+                            if (i == pagenum + newsz)
+                            {
+                                debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize);
+                                memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz);
 
-                            if (bits)
-                            {
-                                gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
-                                gcx.setBits(pool, biti, bits);
+                                if(hasBitMask) {
+                                    size_t** newBitmaskPtr = cast(size_t**) (baseAddr +
+                                        (PAGESIZE * newsz) - (size_t*).sizeof);
+                                    *newBitmaskPtr = bitMask;
+                                }
+
+                                return p;
                             }
-                            else
+                            if (i == pool.ncommitted)
                             {
-                                bits = gcx.getBits(pool, biti);
+                                auto u = pool.extendPages(pagenum + newsz - pool.ncommitted);
+                                if (u == OPFAIL)
+                                    break;
+                                i = pagenum + newsz;
+                                continue;
                             }
+                            if (pool.pagetable[i] != B_FREE)
+                                break;
+                            i++;
                         }
                     }
-                    p2 = mallocNoSync(size, bits);
-                    if (psize < size)
-                        size = psize;
-                    //debug(PRINTF) printf("\tcopying %d bytes\n",size);
-                    memcpy(p2, p, size);
-                    p = p2;
                 }
             }
+            if (psize < size ||             // if new size is bigger
+                psize > size * 2)           // or less than half
+            {
+                p2 = mallocNoSync(size, bits, bitMask);
+
+                psize -= bitMaskSize;
+                size -= bitMaskSize;
+                if (psize < size)
+                    size = psize;
+                //debug(PRINTF) printf("\tcopying %d bytes\n",size);
+                memcpy(p2, p, size);
+                p = p2;
+            }
         }
         return p;
     }
@@ -721,7 +777,16 @@
         {
             return 0;
         }
-        auto psize = gcx.findSize(p);   // find allocated size
+
+        uint bits;  // Used in the mixin.
+        size_t* bitMask;
+        mixin(bitMaskMixin);
+
+        if(hasBitMask) {
+            minsize += bitMaskSize;
+            maxsize += bitMaskSize;
+        }
+
         if (psize < PAGESIZE)
             return 0;                   // cannot extend buckets
 
@@ -729,7 +794,6 @@
         auto minsz = (minsize + PAGESIZE - 1) / PAGESIZE;
         auto maxsz = (maxsize + PAGESIZE - 1) / PAGESIZE;
 
-        auto pool = gcx.findPool(p);
         auto pagenum = (p - pool.baseAddr) / PAGESIZE;
 
         size_t sz;
@@ -762,7 +826,14 @@
             gcx.cached_size_val = (psz + sz) * PAGESIZE;
         if (p == gcx.cached_info_key)
             gcx.cached_info_val.size = (psz + sz) * PAGESIZE;
-        return (psz + sz) * PAGESIZE;
+
+        size_t newSize = (psz + sz) * PAGESIZE;
+        if(hasBitMask) {
+            newSize -= bitMaskSize;
+            size_t** bitMaskPtr = cast(size_t**) (baseAddr + newSize);
+            *bitMaskPtr = bitMask;
+        }
+        return newSize;
     }
 
 
@@ -932,31 +1003,43 @@
     private size_t sizeOfNoSync(void *p)
     {
         assert (p);
+        p = sentinel_sub(p);
 
+        Pool* pool = gcx.findPool(p);
+        uint bits;
+        if(pool !is null) {
+            auto biti = cast(size_t)(p - pool.baseAddr) / 16;
+            bits = gcx.getBits(pool, biti);
+        } else {
+            return 0;
+        }
+
+        size_t size = gcx.findSize(p, pool);
+        size_t bitMaskSize = (size_t*).sizeof * !(BlkAttr.NO_SCAN & bits);
+
         version (SENTINEL)
         {
-            p = sentinel_sub(p);
-            size_t size = gcx.findSize(p);
 
             // Check for interior pointer
             // This depends on:
             // 1) size is a power of 2 for less than PAGESIZE values
             // 2) base of memory pool is aligned on PAGESIZE boundary
-            if (cast(size_t)p & (size - 1) & (PAGESIZE - 1))
-                size = 0;
-            return size ? size - SENTINEL_EXTRA : 0;
+            if (cast(size_t)p & (size - 1) & (PAGESIZE - 1)) {
+                return 0;
+            }
+
+            return size - SENTINEL_EXTRA - bitMaskSize;
         }
         else
         {
-            size_t size = gcx.findSize(p);
-
             // Check for interior pointer
             // This depends on:
             // 1) size is a power of 2 for less than PAGESIZE values
             // 2) base of memory pool is aligned on PAGESIZE boundary
-            if (cast(size_t)p & (size - 1) & (PAGESIZE - 1))
+            if (cast(size_t)p & (size - 1) & (PAGESIZE - 1)) {
                 return 0;
-            return size;
+            }
+            return size - bitMaskSize;
         }
     }
 
@@ -991,7 +1074,11 @@
     {
         assert(p);
 
-        return gcx.getInfo(p);
+        auto ret = gcx.getInfo(p);
+        if( !(ret.attr & BlkAttr.NO_SCAN)) {
+            ret.size -= (size_t*).sizeof;
+        }
+        return ret;
     }
 
 
@@ -1356,7 +1443,14 @@
     B_MAX
 }
 
+/// Translates a bin number in the enum above into a bin size.
+size_t binSize(size_t binNum) {
+    assert(binNum <= B_2048);
+    size_t result = 16 << binNum;
+    return result;
+}
 
+
 alias ubyte Bins;
 
 
@@ -1396,10 +1490,10 @@
     {
         void thread_Invariant() { }
     }
-    
+
     void *cached_size_key;
     size_t cached_size_val;
-    
+
     void *cached_info_key;
     BlkInfo cached_info_val;
 
@@ -1684,9 +1778,10 @@
      */
     void* findBase(void *p)
     {
-        Pool *pool;
+        return findBase(p, findPool(p));
+    }
 
-        pool = findPool(p);
+    void* findBase(void* p, Pool* pool) {
         if (pool)
         {
             size_t offset = cast(size_t)(p - pool.baseAddr);
@@ -1722,13 +1817,15 @@
      */
     size_t findSize(void *p)
     {
-        Pool*  pool;
+        if (USE_CACHE && p == cached_size_key) {
+            return cached_size_val;
+        } else {
+            return findSize(p, findPool(p));
+        }
+    }
+
+    size_t findSize(void *p, Pool* pool) {
         size_t size = 0;
-
-        if (USE_CACHE && p == cached_size_key)
-            return cached_size_val;
-            
-        pool = findPool(p);
         if (pool)
         {
             size_t pagenum;
@@ -1764,7 +1861,7 @@
     {
         Pool*   pool;
         BlkInfo info;
-        
+
         if (USE_CACHE && p == cached_info_key)
             return cached_info_val;
 
@@ -1819,7 +1916,10 @@
             ////////////////////////////////////////////////////////////////////
 
             info.attr = getBits(pool, cast(size_t)(offset / 16));
-            
+            if( !(info.attr & BlkAttr.NO_SCAN)) {
+                info.size -= (size_t*).sizeof;  // bitmask.
+            }
+
             cached_info_key = p;
             cached_info_val = info;
         }
@@ -2129,28 +2229,34 @@
         return 1;
     }
 
+    /**Marks a range of memory using the conservative bit mask.  Used for
+     * the stack.
+     */
+    void markConservative(void* p1, void* p2) {
+        mark(p1, p2, conservativeBitMask.ptr);
+    }
 
+
     /**
      * Search a range of memory values and mark any pointers into the GC pool.
      */
-    void mark(void *pbot, void *ptop)
+    void mark(void *pbot, void *ptop, size_t* bitMask)
     {
         void **p1 = cast(void **)pbot;
         void **p2 = cast(void **)ptop;
         size_t pcache = 0;
         uint changes = 0;
 
-        //printf("marking range: %p -> %p\n", pbot, ptop);
-        for (; p1 < p2; p1++)
-        {
+        void doMark(void** pIn) {
+            debug(COLLECT_LOOP_PRINTF) printf("Marking %p\n", pIn);
             Pool *pool;
-            byte *p = cast(byte *)(*p1);
+            byte *p = cast(byte *)(*pIn);
 
             //if (log) debug(PRINTF) printf("\tmark %x\n", p);
             if (p >= minAddr && p < maxAddr)
             {
                 if ((cast(size_t)p & ~(PAGESIZE-1)) == pcache)
-                    continue;
+                    return;
 
                 pool = findPool(p);
                 if (pool)
@@ -2178,7 +2284,7 @@
                     else
                     {
                         // Don't mark bits in B_FREE or B_UNCOMMITTED pages
-                        continue;
+                        return;
                     }
 
                     if (bin >= B_PAGE) // Cache B_PAGE and B_PAGEPLUS lookups
@@ -2187,7 +2293,7 @@
                     //debug(PRINTF) printf("\t\tmark(x%x) = %d\n", biti, pool.mark.test(biti));
                     if (!pool.mark.test(biti))
                     {
-                        //if (log) debug(PRINTF) printf("\t\tmarking %x\n", p);
+                        debug(PRINTF) printf("\t\tmarking %x\n", p);
                         pool.mark.set(biti);
                         if (!pool.noscan.test(biti))
                         {
@@ -2199,6 +2305,54 @@
                 }
             }
         }
+
+      //  doMark(bitMask);  // In case the bit mask is stored on the heap.
+
+        // bitMask[0] is length, bitMask[1] is T.sizeof.
+        size_t tSize = bitMask[1];
+        size_t[] maskArr = bitMask[2..bitMask[0]];
+
+        // This is the high order bit of each element of maskArr.  It tells us
+        // whether the element is a static array and should be recursed.
+        // If so, the next element is a pointer to the bitmask for this
+        // static array, and the element after this is the length of the
+        // static array in bytes.
+        enum staticArrayRecurseMask = (cast(size_t) 1) << (size_t.sizeof * 8 - 1);
+        enum notRecurseMask = ~staticArrayRecurseMask;
+
+        debug(COLLECT_PRINTF) {
+            printf("bitmask:  %p  p1:  %p  p2:  %p  tSize:  %d  maskLen:  %d\n",
+                bitMask, p1, p2, tSize, maskArr.length);
+        }
+
+        //printf("marking range: %p -> %p\n", pbot, ptop);
+        while(p1 + tSize <= p2) {
+
+            size_t maskIndex = 0;
+            while(maskIndex < maskArr.length) {
+                debug(COLLECT_LOOP_PRINTF) {
+                    printf("p1:  %p  p2:  %p  tSize:  %d  maskLen:  %d  maskIndex:  %d\n",
+                        p1, p2, tSize, maskArr.length, maskIndex);
+                }
+
+                bool isStaticArray = (maskArr[maskIndex] & staticArrayRecurseMask) != 0;
+                void** currentPtr = p1 + (maskArr[maskIndex] & notRecurseMask);
+
+                if(isStaticArray) {
+                    debug(COLLECT_LOOP_PRINTF) printf("Static array, start address:  %p\n", currentPtr);
+                    assert(maskIndex + 2 < maskArr.length);
+                    mark(currentPtr,
+                         currentPtr + maskArr[maskIndex + 1],
+                         maskArr.ptr + maskIndex + 2);
+                    maskIndex += 2 + maskArr[maskIndex + 2];
+                    continue;
+                }
+
+                doMark(currentPtr);
+                maskIndex++;
+            }
+            p1 += tSize;
+        }
         anychanges |= changes;
     }
 
@@ -2288,8 +2442,10 @@
         {
             if (!noStack)
             {
+                debug(PRINTF) printf(" scan stack bot = %x, top = %x\n", stackTop, stackBottom);
+
                 // Scan stacks and registers for each paused thread
-                thread_scanAll( &mark, stackTop );
+                thread_scanAll( &markConservative, stackTop );
             }
         }
         else
@@ -2299,15 +2455,15 @@
                 // Scan stack for main thread
                 debug(PRINTF) printf(" scan stack bot = %x, top = %x\n", stackTop, stackBottom);
                 version (STACKGROWSDOWN)
-                    mark(stackTop, stackBottom);
+                    markConservative(stackTop, stackBottom);
                 else
-                    mark(stackBottom, stackTop);
+                    markConservative(stackBottom, stackTop);
             }
         }
 
         // Scan roots[]
         debug(COLLECT_PRINTF) printf("scan roots[]\n");
-        mark(roots, roots + nroots);
+        markConservative(roots, roots + nroots);
 
         // Scan ranges[]
         debug(COLLECT_PRINTF) printf("scan ranges[]\n");
@@ -2315,7 +2471,7 @@
         for (n = 0; n < nranges; n++)
         {
             debug(COLLECT_PRINTF) printf("\t%x .. %x\n", ranges[n].pbot, ranges[n].ptop);
-            mark(ranges[n].pbot, ranges[n].ptop);
+            markConservative(ranges[n].pbot, ranges[n].ptop);
         }
         //log--;
 
@@ -2362,7 +2518,12 @@
                         bin = cast(Bins)pool.pagetable[pn];
                         if (bin < B_PAGE)
                         {
-                            mark(o, o + binsize[bin]);
+                            size_t bitMaskOffset = binsize[bin] - (size_t*).sizeof;
+                            size_t* bitMask = *(cast(size_t**) (o + bitMaskOffset));
+
+                            debug(PRINTF) printf("Bitmask:  %p\n", bitMask);
+                            mark(o, o + binsize[bin] - (size_t*).sizeof, bitMask);
+                            //mark(o, o + binsize[bin] - (size_t*).sizeof, conservativeBitMask.ptr);
                         }
                         else if (bin == B_PAGE || bin == B_PAGEPLUS)
                         {
@@ -2374,7 +2535,14 @@
                             u = 1;
                             while (pn + u < pool.ncommitted && pool.pagetable[pn + u] == B_PAGEPLUS)
                                 u++;
-                            mark(o, o + u * PAGESIZE);
+
+                            size_t blockSize = u * PAGESIZE;
+                            size_t bitMaskOffset = blockSize - (size_t*).sizeof;
+                            size_t* bitMask = *(cast(size_t**) (o + bitMaskOffset));
+
+                            debug(PRINTF) printf("Bitmask:  %p\n", bitMask);
+                            mark(o, o + u * PAGESIZE - (size_t*).sizeof, bitMask);
+                            //mark(o, o + u * PAGESIZE - (size_t*).sizeof, conservativeBitMask.ptr);
                         }
                     }
                 }
