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)
@@ -1,872 +1,873 @@
-/**
- * Implementation of associative arrays.
- *
- * Copyright: Copyright Digital Mars 2000 - 2009.
- * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
- * Authors:   Walter Bright, Sean Kelly
- *
- *          Copyright Digital Mars 2000 - 2009.
- * Distributed under the Boost Software License, Version 1.0.
- *    (See accompanying file LICENSE_1_0.txt or copy at
- *          http://www.boost.org/LICENSE_1_0.txt)
- */
-module rt.aaA;
-
-private
-{
-    import core.stdc.stdarg;
-    import core.stdc.string;
-    import core.stdc.stdio;
-
-    enum BlkAttr : uint
-    {
-        FINALIZE = 0b0000_0001,
-        NO_SCAN  = 0b0000_0010,
-        NO_MOVE  = 0b0000_0100,
-        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 );
-    extern (C) void  gc_free( void* p );
-}
-
-// Auto-rehash and pre-allocate - Dave Fladebo
-
-immutable size_t[] prime_list = [
-              97UL,            389UL,
-           1_543UL,          6_151UL,
-          24_593UL,         98_317UL,
-          393_241UL,      1_572_869UL,
-        6_291_469UL,     25_165_843UL,
-      100_663_319UL,    402_653_189UL,
-    1_610_612_741UL,  4_294_967_291UL,
-//  8_589_934_513UL, 17_179_869_143UL
-];
-
-/* This is the type of the return value for dynamic arrays.
- * It should be a type that is returned in registers.
- * Although DMD will return types of Array in registers,
- * gcc will not, so we instead use a 'long'.
- */
-alias long ArrayRet_t;
-
-struct Array
-{
-    size_t length;
-    void* ptr;
-}
-
-struct aaA
-{
-    aaA *left;
-    aaA *right;
-    hash_t hash;
-    /* key   */
-    /* value */
-}
-
-struct BB
-{
-    aaA*[] b;
-    size_t nodes;       // total number of aaA nodes
-    TypeInfo keyti;     // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet()
-}
-
-/* This is the type actually seen by the programmer, although
- * it is completely opaque.
- */
-
-struct AA
-{
-    BB* a;
-}
-
-/**********************************
- * Align to next pointer boundary, so that
- * GC won't be faced with misaligned pointers
- * in value.
- */
-
-size_t aligntsize(size_t tsize)
-{
-    // Is pointer alignment on the x64 4 bytes or 8?
-    return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
-}
-
-extern (C):
-
-/*************************************************
- * Invariant for aa.
- */
-
-/+
-void _aaInvAh(aaA*[] aa)
-{
-    for (size_t i = 0; i < aa.length; i++)
-    {
-        if (aa[i])
-            _aaInvAh_x(aa[i]);
-    }
-}
-
-private int _aaCmpAh_x(aaA *e1, aaA *e2)
-{   int c;
-
-    c = e1.hash - e2.hash;
-    if (c == 0)
-    {
-        c = e1.key.length - e2.key.length;
-        if (c == 0)
-            c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
-    }
-    return c;
-}
-
-private void _aaInvAh_x(aaA *e)
-{
-    hash_t key_hash;
-    aaA *e1;
-    aaA *e2;
-
-    key_hash = getHash(e.key);
-    assert(key_hash == e.hash);
-
-    while (1)
-    {   int c;
-
-        e1 = e.left;
-        if (e1)
-        {
-            _aaInvAh_x(e1);             // ordinary recursion
-            do
-            {
-                c = _aaCmpAh_x(e1, e);
-                assert(c < 0);
-                e1 = e1.right;
-            } while (e1 != null);
-        }
-
-        e2 = e.right;
-        if (e2)
-        {
-            do
-            {
-                c = _aaCmpAh_x(e, e2);
-                assert(c < 0);
-                e2 = e2.left;
-            } while (e2 != null);
-            e = e.right;                // tail recursion
-        }
-        else
-            break;
-    }
-}
-+/
-
-/****************************************************
- * Determine number of entries in associative array.
- */
-
-size_t _aaLen(AA aa)
-in
-{
-    //printf("_aaLen()+\n");
-    //_aaInv(aa);
-}
-out (result)
-{
-    size_t len = 0;
-
-    void _aaLen_x(aaA* ex)
-    {
-        auto e = ex;
-        len++;
-
-        while (1)
-        {
-            if (e.right)
-               _aaLen_x(e.right);
-            e = e.left;
-            if (!e)
-                break;
-            len++;
-        }
-    }
-
-    if (aa.a)
-    {
-        foreach (e; aa.a.b)
-        {
-            if (e)
-                _aaLen_x(e);
-        }
-    }
-    assert(len == result);
-
-    //printf("_aaLen()-\n");
-}
-body
-{
-    return aa.a ? aa.a.nodes : 0;
-}
-
-
-/*************************************************
- * Get pointer to value in associative array indexed by key.
- * Add entry for key if it is not already there.
- */
-
-void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...)
-in
-{
-    assert(aa);
-}
-out (result)
-{
-    assert(result);
-    assert(aa.a);
-    assert(aa.a.b.length);
-    //assert(_aaInAh(*aa.a, key));
-}
-body
-{
-    auto pkey = cast(void *)(&valuesize + 1);
-    size_t i;
-    aaA *e;
-    //printf("keyti = %p\n", keyti);
-    //printf("aa = %p\n", aa);
-    auto keysize = aligntsize(keyti.tsize());
-
-    if (!aa.a)
-        aa.a = new BB();
-    //printf("aa = %p\n", aa);
-    //printf("aa.a = %p\n", aa.a);
-    aa.a.keyti = keyti;
-
-    if (!aa.a.b.length)
-    {
-        alias aaA *pa;
-        auto len = prime_list[0];
-
-        aa.a.b = new pa[len];
-    }
-
-    auto key_hash = keyti.getHash(pkey);
-    //printf("hash = %d\n", key_hash);
-    i = key_hash % aa.a.b.length;
-    auto pe = &aa.a.b[i];
-    while ((e = *pe) !is null)
-    {
-        if (key_hash == e.hash)
-        {
-            auto c = keyti.compare(pkey, e + 1);
-            if (c == 0)
-                goto Lret;
-            pe = (c < 0) ? &e.left : &e.right;
-        }
-        else
-            pe = (key_hash < e.hash) ? &e.left : &e.right;
-    }
-
-    // Not found, create new elem
-    //printf("create new one\n");
-    size_t size = aaA.sizeof + keysize + valuesize;
-    e = cast(aaA *) gc_calloc(size);
-    memcpy(e + 1, pkey, keysize);
-    e.hash = key_hash;
-    *pe = e;
-
-    auto nodes = ++aa.a.nodes;
-    //printf("length = %d, nodes = %d\n", aa.a.b.length, nodes);
-    if (nodes > aa.a.b.length * 4)
-    {
-        //printf("rehash\n");
-        _aaRehash(aa,keyti);
-    }
-
-Lret:
-    return cast(void *)(e + 1) + keysize;
-}
-
-
-/*************************************************
- * Get pointer to value in associative array indexed by key.
- * Returns null if it is not already there.
- */
-
-void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...)
-{
-    //printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
-    if (!aa.a)
-        return null;
-
-    auto pkey = cast(void *)(&valuesize + 1);
-    auto keysize = aligntsize(keyti.tsize());
-    auto len = aa.a.b.length;
-
-    if (len)
-    {
-        auto key_hash = keyti.getHash(pkey);
-        //printf("hash = %d\n", key_hash);
-        size_t i = key_hash % len;
-        auto e = aa.a.b[i];
-        while (e !is null)
-        {
-            if (key_hash == e.hash)
-            {
-                auto c = keyti.compare(pkey, e + 1);
-            if (c == 0)
-                return cast(void *)(e + 1) + keysize;
-                e = (c < 0) ? e.left : e.right;
-            }
-            else
-                e = (key_hash < e.hash) ? e.left : e.right;
-        }
-    }
-    return null;    // not found, caller will throw exception
-}
-
-
-/*************************************************
- * Determine if key is in aa.
- * Returns:
- *      null    not in aa
- *      !=null  in aa, return pointer to value
- */
-
-void* _aaIn(AA aa, TypeInfo keyti, ...)
-in
-{
-}
-out (result)
-{
-    //assert(result == 0 || result == 1);
-}
-body
-{
-    if (aa.a)
-    {
-        auto pkey = cast(void *)(&keyti + 1);
-
-        //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
-        auto len = aa.a.b.length;
-
-        if (len)
-        {
-            auto key_hash = keyti.getHash(pkey);
-            //printf("hash = %d\n", key_hash);
-            size_t i = key_hash % len;
-            auto e = aa.a.b[i];
-            while (e !is null)
-            {
-                if (key_hash == e.hash)
-                {
-                    auto c = keyti.compare(pkey, e + 1);
-                    if (c == 0)
-                        return cast(void *)(e + 1) + aligntsize(keyti.tsize());
-                    e = (c < 0) ? e.left : e.right;
-                }
-                else
-                    e = (key_hash < e.hash) ? e.left : e.right;
-            }
-        }
-    }
-
-    // Not found
-    return null;
-}
-
-/*************************************************
- * Delete key entry in aa[].
- * If key is not in aa[], do nothing.
- */
-
-void _aaDel(AA aa, TypeInfo keyti, ...)
-{
-    auto pkey = cast(void *)(&keyti + 1);
-    aaA *e;
-
-    if (aa.a && aa.a.b.length)
-    {
-        auto key_hash = keyti.getHash(pkey);
-        //printf("hash = %d\n", key_hash);
-        size_t i = key_hash % aa.a.b.length;
-        auto pe = &aa.a.b[i];
-        while ((e = *pe) !is null) // null means not found
-        {
-            if (key_hash == e.hash)
-            {
-                auto c = keyti.compare(pkey, e + 1);
-                if (c == 0)
-                {
-                    if (!e.left && !e.right)
-                    {
-                        *pe = null;
-                    }
-                    else if (e.left && !e.right)
-                    {
-                        *pe = e.left;
-                         e.left = null;
-                    }
-                    else if (!e.left && e.right)
-                    {
-                        *pe = e.right;
-                         e.right = null;
-                    }
-                    else
-                    {
-                        *pe = e.left;
-                        e.left = null;
-                        do
-                            pe = &(*pe).right;
-                        while (*pe);
-                        *pe = e.right;
-                        e.right = null;
-                    }
-
-                    aa.a.nodes--;
-                    gc_free(e);
-                    break;
-                }
-                pe = (c < 0) ? &e.left : &e.right;
-            }
-            else
-                pe = (key_hash < e.hash) ? &e.left : &e.right;
-        }
-    }
-}
-
-
-/********************************************
- * Produce array of values from aa.
- */
-
-ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize)
-in
-{
-    assert(keysize == aligntsize(keysize));
-}
-body
-{
-    size_t resi;
-    Array a;
-
-    void _aaValues_x(aaA* e)
-    {
-        do
-        {
-            memcpy(a.ptr + resi * valuesize,
-                   cast(byte*)e + aaA.sizeof + keysize,
-                   valuesize);
-            resi++;
-            if (e.left)
-            {   if (!e.right)
-                {   e = e.left;
-                    continue;
-                }
-                _aaValues_x(e.left);
-            }
-            e = e.right;
-        } while (e !is null);
-    }
-
-    if (aa.a)
-    {
-        a.length = _aaLen(aa);
-        a.ptr = cast(byte*) gc_malloc(a.length * valuesize,
-                                      valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
-        resi = 0;
-        foreach (e; aa.a.b)
-        {
-            if (e)
-                _aaValues_x(e);
-        }
-        assert(resi == a.length);
-    }
-    return *cast(ArrayRet_t*)(&a);
-}
-
-
-/********************************************
- * Rehash an array.
- */
-
-void* _aaRehash(AA* paa, TypeInfo keyti)
-in
-{
-    //_aaInvAh(paa);
-}
-out (result)
-{
-    //_aaInvAh(result);
-}
-body
-{
-    BB newb;
-
-    void _aaRehash_x(aaA* olde)
-    {
-        while (1)
-        {
-            auto left = olde.left;
-            auto right = olde.right;
-            olde.left = null;
-            olde.right = null;
-
-            aaA *e;
-
-            //printf("rehash %p\n", olde);
-            auto key_hash = olde.hash;
-            size_t i = key_hash % newb.b.length;
-            auto pe = &newb.b[i];
-            while ((e = *pe) !is null)
-            {
-                //printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
-                assert(e.left != e);
-                assert(e.right != e);
-                if (key_hash == e.hash)
-                {
-                    auto c = keyti.compare(olde + 1, e + 1);
-                    assert(c != 0);
-                    pe = (c < 0) ? &e.left : &e.right;
-                }
-                else
-                    pe = (key_hash < e.hash) ? &e.left : &e.right;
-            }
-            *pe = olde;
-
-            if (right)
-            {
-                if (!left)
-                {   olde = right;
-                    continue;
-                }
-                _aaRehash_x(right);
-            }
-            if (!left)
-                break;
-            olde = left;
-        }
-    }
-
-    //printf("Rehash\n");
-    if (paa.a)
-    {
-        auto aa = paa.a;
-        auto len = _aaLen(*paa);
-        if (len)
-        {   size_t i;
-
-            for (i = 0; i < prime_list.length - 1; i++)
-            {
-                if (len <= prime_list[i])
-                    break;
-            }
-            len = prime_list[i];
-            newb.b = new aaA*[len];
-
-            foreach (e; aa.b)
-            {
-                if (e)
-                    _aaRehash_x(e);
-            }
-            delete aa.b;
-
-            newb.nodes = aa.nodes;
-            newb.keyti = aa.keyti;
-        }
-
-        *paa.a = newb;
-        _aaBalance(paa);
-    }
-    return (*paa).a;
-}
-
-/********************************************
- * Balance an array.
- */
-
-void _aaBalance(AA* paa)
-{
-    //printf("_aaBalance()\n");
-    if (paa.a)
-    {
-        aaA*[16] tmp;
-        aaA*[] array = tmp;
-        auto aa = paa.a;
-        foreach (j, e; aa.b)
-        {
-            /* Temporarily store contents of bucket in array[]
-             */
-            size_t k = 0;
-            void addToArray(aaA* e)
-            {
-                while (e)
-                {   addToArray(e.left);
-                    if (k == array.length)
-                        array.length = array.length * 2;
-                    array[k++] = e;
-                    e = e.right;
-                }
-            }
-            addToArray(e);
-            /* The contents of the bucket are now sorted into array[].
-             * Rebuild the tree.
-             */
-            void buildTree(aaA** p, size_t x1, size_t x2)
-            {
-                if (x1 >= x2)
-                    *p = null;
-                else
-                {   auto mid = (x1 + x2) >> 1;
-                    *p = array[mid];
-                    buildTree(&(*p).left, x1, mid);
-                    buildTree(&(*p).right, mid + 1, x2);
-                }
-            }
-            auto p = &aa.b[j];
-            buildTree(p, 0, k);
-        }
-    }
-}
-/********************************************
- * Produce array of N byte keys from aa.
- */
-
-ArrayRet_t _aaKeys(AA aa, size_t keysize)
-{
-    byte[] res;
-    size_t resi;
-
-    void _aaKeys_x(aaA* e)
-    {
-        do
-        {
-            memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
-            resi++;
-            if (e.left)
-            {   if (!e.right)
-                {   e = e.left;
-                    continue;
-                }
-                _aaKeys_x(e.left);
-            }
-            e = e.right;
-        } while (e !is null);
-    }
-
-    auto len = _aaLen(aa);
-    if (!len)
-        return 0;
-    res = (cast(byte*) gc_malloc(len * keysize,
-                                 !(aa.a.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0))[0 .. len * keysize];
-    resi = 0;
-    foreach (e; aa.a.b)
-    {
-        if (e)
-            _aaKeys_x(e);
-    }
-    assert(resi == len);
-
-    Array a;
-    a.length = len;
-    a.ptr = res.ptr;
-    return *cast(ArrayRet_t*)(&a);
-}
-
-
-/**********************************************
- * 'apply' for associative arrays - to support foreach
- */
-
-// dg is D, but _aaApply() is C
-extern (D) typedef int delegate(void *) dg_t;
-
-int _aaApply(AA aa, size_t keysize, dg_t dg)
-in
-{
-    assert(aligntsize(keysize) == keysize);
-}
-body
-{   int result;
-
-    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
-
-    int treewalker(aaA* e)
-    {   int result;
-
-        do
-        {
-            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
-            result = dg(cast(void *)(e + 1) + keysize);
-            if (result)
-                break;
-            if (e.right)
-            {   if (!e.left)
-                {
-                    e = e.right;
-                    continue;
-                }
-                result = treewalker(e.right);
-                if (result)
-                    break;
-            }
-            e = e.left;
-        } while (e);
-
-        return result;
-    }
-
-    if (aa.a)
-    {
-        foreach (e; aa.a.b)
-        {
-            if (e)
-            {
-                result = treewalker(e);
-                if (result)
-                    break;
-            }
-        }
-    }
-    return result;
-}
-
-// dg is D, but _aaApply2() is C
-extern (D) typedef int delegate(void *, void *) dg2_t;
-
-int _aaApply2(AA aa, size_t keysize, dg2_t dg)
-in
-{
-    assert(aligntsize(keysize) == keysize);
-}
-body
-{   int result;
-
-    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
-
-    int treewalker(aaA* e)
-    {   int result;
-
-        do
-        {
-            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
-            result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
-            if (result)
-                break;
-            if (e.right)
-            {   if (!e.left)
-                {
-                    e = e.right;
-                    continue;
-                }
-                result = treewalker(e.right);
-                if (result)
-                    break;
-            }
-            e = e.left;
-        } while (e);
-
-        return result;
-    }
-
-    if (aa.a)
-    {
-        foreach (e; aa.a.b)
-        {
-            if (e)
-            {
-                result = treewalker(e);
-                if (result)
-                    break;
-            }
-        }
-    }
-    return result;
-}
-
-
-/***********************************
- * Construct an associative array of type ti from
- * length pairs of key/value pairs.
- */
-
-extern (C)
-BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
-{
-    auto valuesize = ti.next.tsize();           // value size
-    auto keyti = ti.key;
-    auto keysize = keyti.tsize();               // key size
-    BB* result;
-
-    //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
-    //printf("tivalue = %.*s\n", ti.next.classinfo.name);
-    if (length == 0 || valuesize == 0 || keysize == 0)
-    {
-        ;
-    }
-    else
-    {
-        va_list q;
-        va_start!(size_t)(q, length);
-
-        result = new BB();
-        result.keyti = keyti;
-        size_t i;
-
-        for (i = 0; i < prime_list.length - 1; i++)
-        {
-            if (length <= prime_list[i])
-                break;
-        }
-        auto len = prime_list[i];
-        result.b = new aaA*[len];
-
-        size_t keystacksize   = (keysize   + int.sizeof - 1) & ~(int.sizeof - 1);
-        size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
-
-        size_t keytsize = aligntsize(keysize);
-
-        for (size_t j = 0; j < length; j++)
-        {   void* pkey = q;
-            q += keystacksize;
-            void* pvalue = q;
-            q += valuestacksize;
-            aaA* e;
-
-            auto key_hash = keyti.getHash(pkey);
-            //printf("hash = %d\n", key_hash);
-            i = key_hash % len;
-            auto pe = &result.b[i];
-            while (1)
-            {
-                e = *pe;
-                if (!e)
-                {
-                    // Not found, create new elem
-                    //printf("create new one\n");
-                    e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
-                    memcpy(e + 1, pkey, keysize);
-                    e.hash = key_hash;
-                    *pe = e;
-                    result.nodes++;
-                    break;
-                }
-                if (key_hash == e.hash)
-                {
-                    auto c = keyti.compare(pkey, e + 1);
-                    if (c == 0)
-                        break;
-                    pe = (c < 0) ? &e.left : &e.right;
-                }
-                else
-                    pe = (key_hash < e.hash) ? &e.left : &e.right;
-            }
-            memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
-        }
-
-        va_end(q);
-    }
-    return result;
-}
+/**
+ * Implementation of associative arrays.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.aaA;
+
+private
+{
+    import core.stdc.stdarg;
+    import core.stdc.string;
+    import core.stdc.stdio;
+
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    __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 );
+}
+
+// Auto-rehash and pre-allocate - Dave Fladebo
+
+immutable size_t[] prime_list = [
+              97UL,            389UL,
+           1_543UL,          6_151UL,
+          24_593UL,         98_317UL,
+          393_241UL,      1_572_869UL,
+        6_291_469UL,     25_165_843UL,
+      100_663_319UL,    402_653_189UL,
+    1_610_612_741UL,  4_294_967_291UL,
+//  8_589_934_513UL, 17_179_869_143UL
+];
+
+/* This is the type of the return value for dynamic arrays.
+ * It should be a type that is returned in registers.
+ * Although DMD will return types of Array in registers,
+ * gcc will not, so we instead use a 'long'.
+ */
+alias long ArrayRet_t;
+
+struct Array
+{
+    size_t length;
+    void* ptr;
+}
+
+struct aaA
+{
+    aaA *left;
+    aaA *right;
+    hash_t hash;
+    /* key   */
+    /* value */
+}
+
+struct BB
+{
+    aaA*[] b;
+    size_t nodes;       // total number of aaA nodes
+    TypeInfo keyti;     // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet()
+}
+
+/* This is the type actually seen by the programmer, although
+ * it is completely opaque.
+ */
+
+struct AA
+{
+    BB* a;
+}
+
+/**********************************
+ * Align to next pointer boundary, so that
+ * GC won't be faced with misaligned pointers
+ * in value.
+ */
+
+size_t aligntsize(size_t tsize)
+{
+    // Is pointer alignment on the x64 4 bytes or 8?
+    return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
+}
+
+extern (C):
+
+/*************************************************
+ * Invariant for aa.
+ */
+
+/+
+void _aaInvAh(aaA*[] aa)
+{
+    for (size_t i = 0; i < aa.length; i++)
+    {
+        if (aa[i])
+            _aaInvAh_x(aa[i]);
+    }
+}
+
+private int _aaCmpAh_x(aaA *e1, aaA *e2)
+{   int c;
+
+    c = e1.hash - e2.hash;
+    if (c == 0)
+    {
+        c = e1.key.length - e2.key.length;
+        if (c == 0)
+            c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
+    }
+    return c;
+}
+
+private void _aaInvAh_x(aaA *e)
+{
+    hash_t key_hash;
+    aaA *e1;
+    aaA *e2;
+
+    key_hash = getHash(e.key);
+    assert(key_hash == e.hash);
+
+    while (1)
+    {   int c;
+
+        e1 = e.left;
+        if (e1)
+        {
+            _aaInvAh_x(e1);             // ordinary recursion
+            do
+            {
+                c = _aaCmpAh_x(e1, e);
+                assert(c < 0);
+                e1 = e1.right;
+            } while (e1 != null);
+        }
+
+        e2 = e.right;
+        if (e2)
+        {
+            do
+            {
+                c = _aaCmpAh_x(e, e2);
+                assert(c < 0);
+                e2 = e2.left;
+            } while (e2 != null);
+            e = e.right;                // tail recursion
+        }
+        else
+            break;
+    }
+}
++/
+
+/****************************************************
+ * Determine number of entries in associative array.
+ */
+
+size_t _aaLen(AA aa)
+in
+{
+    //printf("_aaLen()+\n");
+    //_aaInv(aa);
+}
+out (result)
+{
+    size_t len = 0;
+
+    void _aaLen_x(aaA* ex)
+    {
+        auto e = ex;
+        len++;
+
+        while (1)
+        {
+            if (e.right)
+               _aaLen_x(e.right);
+            e = e.left;
+            if (!e)
+                break;
+            len++;
+        }
+    }
+
+    if (aa.a)
+    {
+        foreach (e; aa.a.b)
+        {
+            if (e)
+                _aaLen_x(e);
+        }
+    }
+    assert(len == result);
+
+    //printf("_aaLen()-\n");
+}
+body
+{
+    return aa.a ? aa.a.nodes : 0;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Add entry for key if it is not already there.
+ */
+
+void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...)
+in
+{
+    assert(aa);
+}
+out (result)
+{
+    assert(result);
+    assert(aa.a);
+    assert(aa.a.b.length);
+    //assert(_aaInAh(*aa.a, key));
+}
+body
+{
+    auto pkey = cast(void *)(&valuesize + 1);
+    size_t i;
+    aaA *e;
+    //printf("keyti = %p\n", keyti);
+    //printf("aa = %p\n", aa);
+    auto keysize = aligntsize(keyti.tsize());
+
+    if (!aa.a)
+        aa.a = new BB();
+    //printf("aa = %p\n", aa);
+    //printf("aa.a = %p\n", aa.a);
+    aa.a.keyti = keyti;
+
+    if (!aa.a.b.length)
+    {
+        alias aaA *pa;
+        auto len = prime_list[0];
+
+        aa.a.b = new pa[len];
+    }
+
+    auto key_hash = keyti.getHash(pkey);
+    //printf("hash = %d\n", key_hash);
+    i = key_hash % aa.a.b.length;
+    auto pe = &aa.a.b[i];
+    while ((e = *pe) !is null)
+    {
+        if (key_hash == e.hash)
+        {
+            auto c = keyti.compare(pkey, e + 1);
+            if (c == 0)
+                goto Lret;
+            pe = (c < 0) ? &e.left : &e.right;
+        }
+        else
+            pe = (key_hash < e.hash) ? &e.left : &e.right;
+    }
+
+    // Not found, create new elem
+    //printf("create new one\n");
+    size_t size = aaA.sizeof + keysize + valuesize;
+    e = cast(aaA *) gc_calloc(size);
+    memcpy(e + 1, pkey, keysize);
+    e.hash = key_hash;
+    *pe = e;
+
+    auto nodes = ++aa.a.nodes;
+    //printf("length = %d, nodes = %d\n", aa.a.b.length, nodes);
+    if (nodes > aa.a.b.length * 4)
+    {
+        //printf("rehash\n");
+        _aaRehash(aa,keyti);
+    }
+
+Lret:
+    return cast(void *)(e + 1) + keysize;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Returns null if it is not already there.
+ */
+
+void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...)
+{
+    //printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
+    if (!aa.a)
+        return null;
+
+    auto pkey = cast(void *)(&valuesize + 1);
+    auto keysize = aligntsize(keyti.tsize());
+    auto len = aa.a.b.length;
+
+    if (len)
+    {
+        auto key_hash = keyti.getHash(pkey);
+        //printf("hash = %d\n", key_hash);
+        size_t i = key_hash % len;
+        auto e = aa.a.b[i];
+        while (e !is null)
+        {
+            if (key_hash == e.hash)
+            {
+                auto c = keyti.compare(pkey, e + 1);
+            if (c == 0)
+                return cast(void *)(e + 1) + keysize;
+                e = (c < 0) ? e.left : e.right;
+            }
+            else
+                e = (key_hash < e.hash) ? e.left : e.right;
+        }
+    }
+    return null;    // not found, caller will throw exception
+}
+
+
+/*************************************************
+ * Determine if key is in aa.
+ * Returns:
+ *      null    not in aa
+ *      !=null  in aa, return pointer to value
+ */
+
+void* _aaIn(AA aa, TypeInfo keyti, ...)
+in
+{
+}
+out (result)
+{
+    //assert(result == 0 || result == 1);
+}
+body
+{
+    if (aa.a)
+    {
+        auto pkey = cast(void *)(&keyti + 1);
+
+        //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
+        auto len = aa.a.b.length;
+
+        if (len)
+        {
+            auto key_hash = keyti.getHash(pkey);
+            //printf("hash = %d\n", key_hash);
+            size_t i = key_hash % len;
+            auto e = aa.a.b[i];
+            while (e !is null)
+            {
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(pkey, e + 1);
+                    if (c == 0)
+                        return cast(void *)(e + 1) + aligntsize(keyti.tsize());
+                    e = (c < 0) ? e.left : e.right;
+                }
+                else
+                    e = (key_hash < e.hash) ? e.left : e.right;
+            }
+        }
+    }
+
+    // Not found
+    return null;
+}
+
+/*************************************************
+ * Delete key entry in aa[].
+ * If key is not in aa[], do nothing.
+ */
+
+void _aaDel(AA aa, TypeInfo keyti, ...)
+{
+    auto pkey = cast(void *)(&keyti + 1);
+    aaA *e;
+
+    if (aa.a && aa.a.b.length)
+    {
+        auto key_hash = keyti.getHash(pkey);
+        //printf("hash = %d\n", key_hash);
+        size_t i = key_hash % aa.a.b.length;
+        auto pe = &aa.a.b[i];
+        while ((e = *pe) !is null) // null means not found
+        {
+            if (key_hash == e.hash)
+            {
+                auto c = keyti.compare(pkey, e + 1);
+                if (c == 0)
+                {
+                    if (!e.left && !e.right)
+                    {
+                        *pe = null;
+                    }
+                    else if (e.left && !e.right)
+                    {
+                        *pe = e.left;
+                         e.left = null;
+                    }
+                    else if (!e.left && e.right)
+                    {
+                        *pe = e.right;
+                         e.right = null;
+                    }
+                    else
+                    {
+                        *pe = e.left;
+                        e.left = null;
+                        do
+                            pe = &(*pe).right;
+                        while (*pe);
+                        *pe = e.right;
+                        e.right = null;
+                    }
+
+                    aa.a.nodes--;
+                    gc_free(e);
+                    break;
+                }
+                pe = (c < 0) ? &e.left : &e.right;
+            }
+            else
+                pe = (key_hash < e.hash) ? &e.left : &e.right;
+        }
+    }
+}
+
+
+/********************************************
+ * Produce array of values from aa.
+ */
+
+ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize)
+in
+{
+    assert(keysize == aligntsize(keysize));
+}
+body
+{
+    size_t resi;
+    Array a;
+
+    void _aaValues_x(aaA* e)
+    {
+        do
+        {
+            memcpy(a.ptr + resi * valuesize,
+                   cast(byte*)e + aaA.sizeof + keysize,
+                   valuesize);
+            resi++;
+            if (e.left)
+            {   if (!e.right)
+                {   e = e.left;
+                    continue;
+                }
+                _aaValues_x(e.left);
+            }
+            e = e.right;
+        } while (e !is null);
+    }
+
+    if (aa.a)
+    {
+        a.length = _aaLen(aa);
+        a.ptr = cast(byte*) gc_malloc(a.length * valuesize,
+                                      valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
+        resi = 0;
+        foreach (e; aa.a.b)
+        {
+            if (e)
+                _aaValues_x(e);
+        }
+        assert(resi == a.length);
+    }
+    return *cast(ArrayRet_t*)(&a);
+}
+
+
+/********************************************
+ * Rehash an array.
+ */
+
+void* _aaRehash(AA* paa, TypeInfo keyti)
+in
+{
+    //_aaInvAh(paa);
+}
+out (result)
+{
+    //_aaInvAh(result);
+}
+body
+{
+    BB newb;
+
+    void _aaRehash_x(aaA* olde)
+    {
+        while (1)
+        {
+            auto left = olde.left;
+            auto right = olde.right;
+            olde.left = null;
+            olde.right = null;
+
+            aaA *e;
+
+            //printf("rehash %p\n", olde);
+            auto key_hash = olde.hash;
+            size_t i = key_hash % newb.b.length;
+            auto pe = &newb.b[i];
+            while ((e = *pe) !is null)
+            {
+                //printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
+                assert(e.left != e);
+                assert(e.right != e);
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(olde + 1, e + 1);
+                    assert(c != 0);
+                    pe = (c < 0) ? &e.left : &e.right;
+                }
+                else
+                    pe = (key_hash < e.hash) ? &e.left : &e.right;
+            }
+            *pe = olde;
+
+            if (right)
+            {
+                if (!left)
+                {   olde = right;
+                    continue;
+                }
+                _aaRehash_x(right);
+            }
+            if (!left)
+                break;
+            olde = left;
+        }
+    }
+
+    //printf("Rehash\n");
+    if (paa.a)
+    {
+        auto aa = paa.a;
+        auto len = _aaLen(*paa);
+        if (len)
+        {   size_t i;
+
+            for (i = 0; i < prime_list.length - 1; i++)
+            {
+                if (len <= prime_list[i])
+                    break;
+            }
+            len = prime_list[i];
+            newb.b = new aaA*[len];
+
+            foreach (e; aa.b)
+            {
+                if (e)
+                    _aaRehash_x(e);
+            }
+            delete aa.b;
+
+            newb.nodes = aa.nodes;
+            newb.keyti = aa.keyti;
+        }
+
+        *paa.a = newb;
+        _aaBalance(paa);
+    }
+    return (*paa).a;
+}
+
+/********************************************
+ * Balance an array.
+ */
+
+void _aaBalance(AA* paa)
+{
+    //printf("_aaBalance()\n");
+    if (paa.a)
+    {
+        aaA*[16] tmp;
+        aaA*[] array = tmp;
+        auto aa = paa.a;
+        foreach (j, e; aa.b)
+        {
+            /* Temporarily store contents of bucket in array[]
+             */
+            size_t k = 0;
+            void addToArray(aaA* e)
+            {
+                while (e)
+                {   addToArray(e.left);
+                    if (k == array.length)
+                        array.length = array.length * 2;
+                    array[k++] = e;
+                    e = e.right;
+                }
+            }
+            addToArray(e);
+            /* The contents of the bucket are now sorted into array[].
+             * Rebuild the tree.
+             */
+            void buildTree(aaA** p, size_t x1, size_t x2)
+            {
+                if (x1 >= x2)
+                    *p = null;
+                else
+                {   auto mid = (x1 + x2) >> 1;
+                    *p = array[mid];
+                    buildTree(&(*p).left, x1, mid);
+                    buildTree(&(*p).right, mid + 1, x2);
+                }
+            }
+            auto p = &aa.b[j];
+            buildTree(p, 0, k);
+        }
+    }
+}
+/********************************************
+ * Produce array of N byte keys from aa.
+ */
+
+ArrayRet_t _aaKeys(AA aa, size_t keysize)
+{
+    byte[] res;
+    size_t resi;
+
+    void _aaKeys_x(aaA* e)
+    {
+        do
+        {
+            memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
+            resi++;
+            if (e.left)
+            {   if (!e.right)
+                {   e = e.left;
+                    continue;
+                }
+                _aaKeys_x(e.left);
+            }
+            e = e.right;
+        } while (e !is null);
+    }
+
+    auto len = _aaLen(aa);
+    if (!len)
+        return 0;
+    res = (cast(byte*) gc_malloc(len * keysize,
+                                 !(aa.a.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0))[0 .. len * keysize];
+    resi = 0;
+    foreach (e; aa.a.b)
+    {
+        if (e)
+            _aaKeys_x(e);
+    }
+    assert(resi == len);
+
+    Array a;
+    a.length = len;
+    a.ptr = res.ptr;
+    return *cast(ArrayRet_t*)(&a);
+}
+
+
+/**********************************************
+ * 'apply' for associative arrays - to support foreach
+ */
+
+// dg is D, but _aaApply() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+int _aaApply(AA aa, size_t keysize, dg_t dg)
+in
+{
+    assert(aligntsize(keysize) == keysize);
+}
+body
+{   int result;
+
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
+
+    int treewalker(aaA* e)
+    {   int result;
+
+        do
+        {
+            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
+            result = dg(cast(void *)(e + 1) + keysize);
+            if (result)
+                break;
+            if (e.right)
+            {   if (!e.left)
+                {
+                    e = e.right;
+                    continue;
+                }
+                result = treewalker(e.right);
+                if (result)
+                    break;
+            }
+            e = e.left;
+        } while (e);
+
+        return result;
+    }
+
+    if (aa.a)
+    {
+        foreach (e; aa.a.b)
+        {
+            if (e)
+            {
+                result = treewalker(e);
+                if (result)
+                    break;
+            }
+        }
+    }
+    return result;
+}
+
+// dg is D, but _aaApply2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+int _aaApply2(AA aa, size_t keysize, dg2_t dg)
+in
+{
+    assert(aligntsize(keysize) == keysize);
+}
+body
+{   int result;
+
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
+
+    int treewalker(aaA* e)
+    {   int result;
+
+        do
+        {
+            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
+            result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
+            if (result)
+                break;
+            if (e.right)
+            {   if (!e.left)
+                {
+                    e = e.right;
+                    continue;
+                }
+                result = treewalker(e.right);
+                if (result)
+                    break;
+            }
+            e = e.left;
+        } while (e);
+
+        return result;
+    }
+
+    if (aa.a)
+    {
+        foreach (e; aa.a.b)
+        {
+            if (e)
+            {
+                result = treewalker(e);
+                if (result)
+                    break;
+            }
+        }
+    }
+    return result;
+}
+
+
+/***********************************
+ * Construct an associative array of type ti from
+ * length pairs of key/value pairs.
+ */
+
+extern (C)
+BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
+{
+    auto valuesize = ti.next.tsize();           // value size
+    auto keyti = ti.key;
+    auto keysize = keyti.tsize();               // key size
+    BB* result;
+
+    //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
+    //printf("tivalue = %.*s\n", ti.next.classinfo.name);
+    if (length == 0 || valuesize == 0 || keysize == 0)
+    {
+        ;
+    }
+    else
+    {
+        va_list q;
+        va_start!(size_t)(q, length);
+
+        result = new BB();
+        result.keyti = keyti;
+        size_t i;
+
+        for (i = 0; i < prime_list.length - 1; i++)
+        {
+            if (length <= prime_list[i])
+                break;
+        }
+        auto len = prime_list[i];
+        result.b = new aaA*[len];
+
+        size_t keystacksize   = (keysize   + int.sizeof - 1) & ~(int.sizeof - 1);
+        size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
+
+        size_t keytsize = aligntsize(keysize);
+
+        for (size_t j = 0; j < length; j++)
+        {   void* pkey = q;
+            q += keystacksize;
+            void* pvalue = q;
+            q += valuestacksize;
+            aaA* e;
+
+            auto key_hash = keyti.getHash(pkey);
+            //printf("hash = %d\n", key_hash);
+            i = key_hash % len;
+            auto pe = &result.b[i];
+            while (1)
+            {
+                e = *pe;
+                if (!e)
+                {
+                    // Not found, create new elem
+                    //printf("create new one\n");
+                    e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
+                    memcpy(e + 1, pkey, keysize);
+                    e.hash = key_hash;
+                    *pe = e;
+                    result.nodes++;
+                    break;
+                }
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(pkey, e + 1);
+                    if (c == 0)
+                        break;
+                    pe = (c < 0) ? &e.left : &e.right;
+                }
+                else
+                    pe = (key_hash < e.hash) ? &e.left : &e.right;
+            }
+            memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
+        }
+
+        va_end(q);
+    }
+    return result;
+}
Index: src/compiler/dmd/rt/adi.d
===================================================================
--- src/compiler/dmd/rt/adi.d	(revision 185)
+++ src/compiler/dmd/rt/adi.d	(working copy)
@@ -1,603 +1,604 @@
-/**
- * Implementation of dynamic array property support routines.
- *
- * Copyright: Copyright Digital Mars 2000 - 2009.
- * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
- * Authors:   Walter Bright
- *
- *          Copyright Digital Mars 2000 - 2009.
- * Distributed under the Boost Software License, Version 1.0.
- *    (See accompanying file LICENSE_1_0.txt or copy at
- *          http://www.boost.org/LICENSE_1_0.txt)
- */
-module rt.adi;
-
-//debug=adi;            // uncomment to turn on debugging printf's
-
-private
-{
-    debug(adi) import core.stdc.stdio;
-    import core.stdc.string;
-    import core.stdc.stdlib;
-    import rt.util.utf;
-
-    enum BlkAttr : uint
-    {
-        FINALIZE = 0b0000_0001,
-        NO_SCAN  = 0b0000_0010,
-        NO_MOVE  = 0b0000_0100,
-        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 );
-    extern (C) void  gc_free( void* p );
-}
-
-
-struct Array
-{
-    size_t  length;
-    void*   ptr;
-}
-
-/**********************************************
- * Reverse array of chars.
- * Handled separately because embedded multibyte encodings should not be
- * reversed.
- */
-
-extern (C) long _adReverseChar(char[] a)
-{
-    if (a.length > 1)
-    {
-        char[6] tmp;
-        char[6] tmplo;
-        char* lo = a.ptr;
-        char* hi = &a[length - 1];
-
-        while (lo < hi)
-        {   auto clo = *lo;
-            auto chi = *hi;
-
-            debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
-            if (clo <= 0x7F && chi <= 0x7F)
-            {
-                debug(adi) printf("\tascii\n");
-                *lo = chi;
-                *hi = clo;
-                lo++;
-                hi--;
-                continue;
-            }
-
-            uint stridelo = UTF8stride[clo];
-
-            uint stridehi = 1;
-            while ((chi & 0xC0) == 0x80)
-            {
-                chi = *--hi;
-                stridehi++;
-                assert(hi >= lo);
-            }
-            if (lo == hi)
-                break;
-
-            debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
-            if (stridelo == stridehi)
-            {
-
-                memcpy(tmp.ptr, lo, stridelo);
-                memcpy(lo, hi, stridelo);
-                memcpy(hi, tmp.ptr, stridelo);
-                lo += stridelo;
-                hi--;
-                continue;
-            }
-
-            /* Shift the whole array. This is woefully inefficient
-             */
-            memcpy(tmp.ptr, hi, stridehi);
-            memcpy(tmplo.ptr, lo, stridelo);
-            memmove(lo + stridehi, lo + stridelo , (hi - lo) - stridelo);
-            memcpy(lo, tmp.ptr, stridehi);
-            memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
-
-            lo += stridehi;
-            hi = hi - 1 + (stridehi - stridelo);
-        }
-    }
-    return *cast(long*)(&a);
-}
-
-unittest
-{
-    auto a = "abcd"c[];
-
-    auto r = a.dup.reverse;
-    //writefln(r);
-    assert(r == "dcba");
-
-    a = "a\u1235\u1234c";
-    //writefln(a);
-    r = a.dup.reverse;
-    //writefln(r);
-    assert(r == "c\u1234\u1235a");
-
-    a = "ab\u1234c";
-    //writefln(a);
-    r = a.dup.reverse;
-    //writefln(r);
-    assert(r == "c\u1234ba");
-
-    a = "\u3026\u2021\u3061\n";
-    r = a.dup.reverse;
-    assert(r == "\n\u3061\u2021\u3026");
-}
-
-
-/**********************************************
- * Reverse array of wchars.
- * Handled separately because embedded multiword encodings should not be
- * reversed.
- */
-
-extern (C) long _adReverseWchar(wchar[] a)
-{
-    if (a.length > 1)
-    {
-        wchar[2] tmp;
-        wchar* lo = a.ptr;
-        wchar* hi = &a[length - 1];
-
-        while (lo < hi)
-        {   auto clo = *lo;
-            auto chi = *hi;
-
-            if ((clo < 0xD800 || clo > 0xDFFF) &&
-                (chi < 0xD800 || chi > 0xDFFF))
-            {
-                *lo = chi;
-                *hi = clo;
-                lo++;
-                hi--;
-                continue;
-            }
-
-            int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
-
-            int stridehi = 1;
-            if (chi >= 0xDC00 && chi <= 0xDFFF)
-            {
-                chi = *--hi;
-                stridehi++;
-                assert(hi >= lo);
-            }
-            if (lo == hi)
-                break;
-
-            if (stridelo == stridehi)
-            {   int stmp;
-
-                assert(stridelo == 2);
-                assert(stmp.sizeof == 2 * (*lo).sizeof);
-                stmp = *cast(int*)lo;
-                *cast(int*)lo = *cast(int*)hi;
-                *cast(int*)hi = stmp;
-                lo += stridelo;
-                hi--;
-                continue;
-            }
-
-            /* Shift the whole array. This is woefully inefficient
-             */
-            memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
-            memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
-            memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
-            memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
-
-            lo += stridehi;
-            hi = hi - 1 + (stridehi - stridelo);
-        }
-    }
-    return *cast(long*)(&a);
-}
-
-unittest
-{
-    wstring a = "abcd";
-
-    auto r = a.dup.reverse;
-    assert(r == "dcba");
-
-    a = "a\U00012356\U00012346c";
-    r = a.dup.reverse;
-    assert(r == "c\U00012346\U00012356a");
-
-    a = "ab\U00012345c";
-    r = a.dup.reverse;
-    assert(r == "c\U00012345ba");
-}
-
-
-/**********************************************
- * Support for array.reverse property.
- */
-
-extern (C) long _adReverse(Array a, size_t szelem)
-out (result)
-{
-    assert(result is *cast(long*)(&a));
-}
-body
-{
-    if (a.length >= 2)
-    {
-        byte*    tmp;
-        byte[16] buffer;
-
-        void* lo = a.ptr;
-        void* hi = a.ptr + (a.length - 1) * szelem;
-
-        tmp = buffer.ptr;
-        if (szelem > 16)
-        {
-            //version (Windows)
-                tmp = cast(byte*) alloca(szelem);
-            //else
-                //tmp = gc_malloc(szelem);
-        }
-
-        for (; lo < hi; lo += szelem, hi -= szelem)
-        {
-            memcpy(tmp, lo,  szelem);
-            memcpy(lo,  hi,  szelem);
-            memcpy(hi,  tmp, szelem);
-        }
-
-        version (Windows)
-        {
-        }
-        else
-        {
-            //if (szelem > 16)
-                // BUG: bad code is generate for delete pointer, tries
-                // to call delclass.
-                //gc_free(tmp);
-        }
-    }
-    return *cast(long*)(&a);
-}
-
-unittest
-{
-    debug(adi) printf("array.reverse.unittest\n");
-
-    int[] a = new int[5];
-    int[] b;
-    size_t i;
-
-    for (i = 0; i < 5; i++)
-        a[i] = i;
-    b = a.reverse;
-    assert(b is a);
-    for (i = 0; i < 5; i++)
-        assert(a[i] == 4 - i);
-
-    struct X20
-    {   // More than 16 bytes in size
-        int a;
-        int b, c, d, e;
-    }
-
-    X20[] c = new X20[5];
-    X20[] d;
-
-    for (i = 0; i < 5; i++)
-    {   c[i].a = i;
-        c[i].e = 10;
-    }
-    d = c.reverse;
-    assert(d is c);
-    for (i = 0; i < 5; i++)
-    {
-        assert(c[i].a == 4 - i);
-        assert(c[i].e == 10);
-    }
-}
-
-/**********************************************
- * Sort array of chars.
- */
-
-extern (C) long _adSortChar(char[] a)
-{
-    if (a.length > 1)
-    {
-        dstring da = toUTF32(a);
-        da.sort;
-        size_t i = 0;
-        foreach (dchar d; da)
-        {   char[4] buf;
-            auto t = toUTF8(buf, d);
-            a[i .. i + t.length] = t[];
-            i += t.length;
-        }
-        delete da;
-    }
-    return *cast(long*)(&a);
-}
-
-/**********************************************
- * Sort array of wchars.
- */
-
-extern (C) long _adSortWchar(wchar[] a)
-{
-    if (a.length > 1)
-    {
-        dstring da = toUTF32(a);
-        da.sort;
-        size_t i = 0;
-        foreach (dchar d; da)
-        {   wchar[2] buf;
-            auto t = toUTF16(buf, d);
-            a[i .. i + t.length] = t[];
-            i += t.length;
-        }
-        delete da;
-    }
-    return *cast(long*)(&a);
-}
-
-/***************************************
- * Support for array equality test.
- * Returns:
- *      1       equal
- *      0       not equal
- */
-
-extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
-{
-    debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
-    if (a1.length != a2.length)
-        return 0; // not equal
-    auto sz = ti.tsize();
-    auto p1 = a1.ptr;
-    auto p2 = a2.ptr;
-
-    if (sz == 1)
-        // We should really have a ti.isPOD() check for this
-        return (memcmp(p1, p2, a1.length) == 0);
-
-    for (size_t i = 0; i < a1.length; i++)
-    {
-        if (!ti.equals(p1 + i * sz, p2 + i * sz))
-            return 0; // not equal
-    }
-    return 1; // equal
-}
-
-extern (C) int _adEq2(Array a1, Array a2, TypeInfo ti)
-{
-    debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
-    if (a1.length != a2.length)
-        return 0;               // not equal
-    if (!ti.equals(&a1, &a2))
-        return 0;
-    return 1;
-}
-unittest
-{
-    debug(adi) printf("array.Eq unittest\n");
-
-    auto a = "hello"c;
-
-    assert(a != "hel");
-    assert(a != "helloo");
-    assert(a != "betty");
-    assert(a == "hello");
-    assert(a != "hxxxx");
-}
-
-/***************************************
- * Support for array compare test.
- */
-
-extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
-{
-    debug(adi) printf("adCmp()\n");
-    auto len = a1.length;
-    if (a2.length < len)
-        len = a2.length;
-    auto sz = ti.tsize();
-    void *p1 = a1.ptr;
-    void *p2 = a2.ptr;
-
-    if (sz == 1)
-    {   // We should really have a ti.isPOD() check for this
-        auto c = memcmp(p1, p2, len);
-        if (c)
-            return c;
-    }
-    else
-    {
-        for (size_t i = 0; i < len; i++)
-        {
-            auto c = ti.compare(p1 + i * sz, p2 + i * sz);
-            if (c)
-                return c;
-        }
-    }
-    if (a1.length == a2.length)
-        return 0;
-    return (a1.length > a2.length) ? 1 : -1;
-}
-
-extern (C) int _adCmp2(Array a1, Array a2, TypeInfo ti)
-{
-    debug(adi) printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
-    return ti.compare(&a1, &a2);
-}
-unittest
-{
-    debug(adi) printf("array.Cmp unittest\n");
-
-    auto a = "hello"c;
-
-    assert(a >  "hel");
-    assert(a >= "hel");
-    assert(a <  "helloo");
-    assert(a <= "helloo");
-    assert(a >  "betty");
-    assert(a >= "betty");
-    assert(a == "hello");
-    assert(a <= "hello");
-    assert(a >= "hello");
-}
-
-/***************************************
- * Support for array compare test.
- */
-
-extern (C) int _adCmpChar(Array a1, Array a2)
-{
-  version (X86)
-  {
-    asm
-    {   naked                   ;
-
-        push    EDI             ;
-        push    ESI             ;
-
-        mov    ESI,a1+4[4+ESP]  ;
-        mov    EDI,a2+4[4+ESP]  ;
-
-        mov    ECX,a1[4+ESP]    ;
-        mov    EDX,a2[4+ESP]    ;
-
-        cmp     ECX,EDX         ;
-        jb      GotLength       ;
-
-        mov     ECX,EDX         ;
-
-GotLength:
-        cmp    ECX,4            ;
-        jb    DoBytes           ;
-
-        // Do alignment if neither is dword aligned
-        test    ESI,3           ;
-        jz    Aligned           ;
-
-        test    EDI,3           ;
-        jz    Aligned           ;
-DoAlign:
-        mov    AL,[ESI]         ; //align ESI to dword bounds
-        mov    DL,[EDI]         ;
-
-        cmp    AL,DL            ;
-        jnz    Unequal          ;
-
-        inc    ESI              ;
-        inc    EDI              ;
-
-        test    ESI,3           ;
-
-        lea    ECX,[ECX-1]      ;
-        jnz    DoAlign          ;
-Aligned:
-        mov    EAX,ECX          ;
-
-        // do multiple of 4 bytes at a time
-
-        shr    ECX,2            ;
-        jz    TryOdd            ;
-
-        repe                    ;
-        cmpsd                   ;
-
-        jnz    UnequalQuad      ;
-
-TryOdd:
-        mov    ECX,EAX          ;
-DoBytes:
-        // if still equal and not end of string, do up to 3 bytes slightly
-        // slower.
-
-        and    ECX,3            ;
-        jz    Equal             ;
-
-        repe                    ;
-        cmpsb                   ;
-
-        jnz    Unequal          ;
-Equal:
-        mov    EAX,a1[4+ESP]    ;
-        mov    EDX,a2[4+ESP]    ;
-
-        sub    EAX,EDX          ;
-        pop    ESI              ;
-
-        pop    EDI              ;
-        ret                     ;
-
-UnequalQuad:
-        mov    EDX,[EDI-4]      ;
-        mov    EAX,[ESI-4]      ;
-
-        cmp    AL,DL            ;
-        jnz    Unequal          ;
-
-        cmp    AH,DH            ;
-        jnz    Unequal          ;
-
-        shr    EAX,16           ;
-
-        shr    EDX,16           ;
-
-        cmp    AL,DL            ;
-        jnz    Unequal          ;
-
-        cmp    AH,DH            ;
-Unequal:
-        sbb    EAX,EAX          ;
-        pop    ESI              ;
-
-        or     EAX,1            ;
-        pop    EDI              ;
-
-        ret                     ;
-    }
-  }
-  else
-  {
-    int len;
-    int c;
-
-    debug(adi) printf("adCmpChar()\n");
-    len = a1.length;
-    if (a2.length < len)
-        len = a2.length;
-    c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
-    if (!c)
-        c = cast(int)a1.length - cast(int)a2.length;
-    return c;
-  }
-}
-
-unittest
-{
-    debug(adi) printf("array.CmpChar unittest\n");
-
-    auto a = "hello"c;
-
-    assert(a >  "hel");
-    assert(a >= "hel");
-    assert(a <  "helloo");
-    assert(a <= "helloo");
-    assert(a >  "betty");
-    assert(a >= "betty");
-    assert(a == "hello");
-    assert(a <= "hello");
-    assert(a >= "hello");
-}
+/**
+ * Implementation of dynamic array property support routines.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.adi;
+
+//debug=adi;            // uncomment to turn on debugging printf's
+
+private
+{
+    debug(adi) import core.stdc.stdio;
+    import core.stdc.string;
+    import core.stdc.stdlib;
+    import rt.util.utf;
+
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    __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 );
+}
+
+
+struct Array
+{
+    size_t  length;
+    void*   ptr;
+}
+
+/**********************************************
+ * Reverse array of chars.
+ * Handled separately because embedded multibyte encodings should not be
+ * reversed.
+ */
+
+extern (C) long _adReverseChar(char[] a)
+{
+    if (a.length > 1)
+    {
+        char[6] tmp;
+        char[6] tmplo;
+        char* lo = a.ptr;
+        char* hi = &a[length - 1];
+
+        while (lo < hi)
+        {   auto clo = *lo;
+            auto chi = *hi;
+
+            debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
+            if (clo <= 0x7F && chi <= 0x7F)
+            {
+                debug(adi) printf("\tascii\n");
+                *lo = chi;
+                *hi = clo;
+                lo++;
+                hi--;
+                continue;
+            }
+
+            uint stridelo = UTF8stride[clo];
+
+            uint stridehi = 1;
+            while ((chi & 0xC0) == 0x80)
+            {
+                chi = *--hi;
+                stridehi++;
+                assert(hi >= lo);
+            }
+            if (lo == hi)
+                break;
+
+            debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
+            if (stridelo == stridehi)
+            {
+
+                memcpy(tmp.ptr, lo, stridelo);
+                memcpy(lo, hi, stridelo);
+                memcpy(hi, tmp.ptr, stridelo);
+                lo += stridelo;
+                hi--;
+                continue;
+            }
+
+            /* Shift the whole array. This is woefully inefficient
+             */
+            memcpy(tmp.ptr, hi, stridehi);
+            memcpy(tmplo.ptr, lo, stridelo);
+            memmove(lo + stridehi, lo + stridelo , (hi - lo) - stridelo);
+            memcpy(lo, tmp.ptr, stridehi);
+            memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
+
+            lo += stridehi;
+            hi = hi - 1 + (stridehi - stridelo);
+        }
+    }
+    return *cast(long*)(&a);
+}
+
+unittest
+{
+    auto a = "abcd"c[];
+
+    auto r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "dcba");
+
+    a = "a\u1235\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234\u1235a");
+
+    a = "ab\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234ba");
+
+    a = "\u3026\u2021\u3061\n";
+    r = a.dup.reverse;
+    assert(r == "\n\u3061\u2021\u3026");
+}
+
+
+/**********************************************
+ * Reverse array of wchars.
+ * Handled separately because embedded multiword encodings should not be
+ * reversed.
+ */
+
+extern (C) long _adReverseWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+        wchar[2] tmp;
+        wchar* lo = a.ptr;
+        wchar* hi = &a[length - 1];
+
+        while (lo < hi)
+        {   auto clo = *lo;
+            auto chi = *hi;
+
+            if ((clo < 0xD800 || clo > 0xDFFF) &&
+                (chi < 0xD800 || chi > 0xDFFF))
+            {
+                *lo = chi;
+                *hi = clo;
+                lo++;
+                hi--;
+                continue;
+            }
+
+            int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
+
+            int stridehi = 1;
+            if (chi >= 0xDC00 && chi <= 0xDFFF)
+            {
+                chi = *--hi;
+                stridehi++;
+                assert(hi >= lo);
+            }
+            if (lo == hi)
+                break;
+
+            if (stridelo == stridehi)
+            {   int stmp;
+
+                assert(stridelo == 2);
+                assert(stmp.sizeof == 2 * (*lo).sizeof);
+                stmp = *cast(int*)lo;
+                *cast(int*)lo = *cast(int*)hi;
+                *cast(int*)hi = stmp;
+                lo += stridelo;
+                hi--;
+                continue;
+            }
+
+            /* Shift the whole array. This is woefully inefficient
+             */
+            memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
+            memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
+            memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
+            memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
+
+            lo += stridehi;
+            hi = hi - 1 + (stridehi - stridelo);
+        }
+    }
+    return *cast(long*)(&a);
+}
+
+unittest
+{
+    wstring a = "abcd";
+
+    auto r = a.dup.reverse;
+    assert(r == "dcba");
+
+    a = "a\U00012356\U00012346c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012346\U00012356a");
+
+    a = "ab\U00012345c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012345ba");
+}
+
+
+/**********************************************
+ * Support for array.reverse property.
+ */
+
+extern (C) long _adReverse(Array a, size_t szelem)
+out (result)
+{
+    assert(result is *cast(long*)(&a));
+}
+body
+{
+    if (a.length >= 2)
+    {
+        byte*    tmp;
+        byte[16] buffer;
+
+        void* lo = a.ptr;
+        void* hi = a.ptr + (a.length - 1) * szelem;
+
+        tmp = buffer.ptr;
+        if (szelem > 16)
+        {
+            //version (Windows)
+                tmp = cast(byte*) alloca(szelem);
+            //else
+                //tmp = gc_malloc(szelem);
+        }
+
+        for (; lo < hi; lo += szelem, hi -= szelem)
+        {
+            memcpy(tmp, lo,  szelem);
+            memcpy(lo,  hi,  szelem);
+            memcpy(hi,  tmp, szelem);
+        }
+
+        version (Windows)
+        {
+        }
+        else
+        {
+            //if (szelem > 16)
+                // BUG: bad code is generate for delete pointer, tries
+                // to call delclass.
+                //gc_free(tmp);
+        }
+    }
+    return *cast(long*)(&a);
+}
+
+unittest
+{
+    debug(adi) printf("array.reverse.unittest\n");
+
+    int[] a = new int[5];
+    int[] b;
+    size_t i;
+
+    for (i = 0; i < 5; i++)
+        a[i] = i;
+    b = a.reverse;
+    assert(b is a);
+    for (i = 0; i < 5; i++)
+        assert(a[i] == 4 - i);
+
+    struct X20
+    {   // More than 16 bytes in size
+        int a;
+        int b, c, d, e;
+    }
+
+    X20[] c = new X20[5];
+    X20[] d;
+
+    for (i = 0; i < 5; i++)
+    {   c[i].a = i;
+        c[i].e = 10;
+    }
+    d = c.reverse;
+    assert(d is c);
+    for (i = 0; i < 5; i++)
+    {
+        assert(c[i].a == 4 - i);
+        assert(c[i].e == 10);
+    }
+}
+
+/**********************************************
+ * Sort array of chars.
+ */
+
+extern (C) long _adSortChar(char[] a)
+{
+    if (a.length > 1)
+    {
+        dstring da = toUTF32(a);
+        da.sort;
+        size_t i = 0;
+        foreach (dchar d; da)
+        {   char[4] buf;
+            auto t = toUTF8(buf, d);
+            a[i .. i + t.length] = t[];
+            i += t.length;
+        }
+        delete da;
+    }
+    return *cast(long*)(&a);
+}
+
+/**********************************************
+ * Sort array of wchars.
+ */
+
+extern (C) long _adSortWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+        dstring da = toUTF32(a);
+        da.sort;
+        size_t i = 0;
+        foreach (dchar d; da)
+        {   wchar[2] buf;
+            auto t = toUTF16(buf, d);
+            a[i .. i + t.length] = t[];
+            i += t.length;
+        }
+        delete da;
+    }
+    return *cast(long*)(&a);
+}
+
+/***************************************
+ * Support for array equality test.
+ * Returns:
+ *      1       equal
+ *      0       not equal
+ */
+
+extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    if (a1.length != a2.length)
+        return 0; // not equal
+    auto sz = ti.tsize();
+    auto p1 = a1.ptr;
+    auto p2 = a2.ptr;
+
+    if (sz == 1)
+        // We should really have a ti.isPOD() check for this
+        return (memcmp(p1, p2, a1.length) == 0);
+
+    for (size_t i = 0; i < a1.length; i++)
+    {
+        if (!ti.equals(p1 + i * sz, p2 + i * sz))
+            return 0; // not equal
+    }
+    return 1; // equal
+}
+
+extern (C) int _adEq2(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    if (a1.length != a2.length)
+        return 0;               // not equal
+    if (!ti.equals(&a1, &a2))
+        return 0;
+    return 1;
+}
+unittest
+{
+    debug(adi) printf("array.Eq unittest\n");
+
+    auto a = "hello"c;
+
+    assert(a != "hel");
+    assert(a != "helloo");
+    assert(a != "betty");
+    assert(a == "hello");
+    assert(a != "hxxxx");
+}
+
+/***************************************
+ * Support for array compare test.
+ */
+
+extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("adCmp()\n");
+    auto len = a1.length;
+    if (a2.length < len)
+        len = a2.length;
+    auto sz = ti.tsize();
+    void *p1 = a1.ptr;
+    void *p2 = a2.ptr;
+
+    if (sz == 1)
+    {   // We should really have a ti.isPOD() check for this
+        auto c = memcmp(p1, p2, len);
+        if (c)
+            return c;
+    }
+    else
+    {
+        for (size_t i = 0; i < len; i++)
+        {
+            auto c = ti.compare(p1 + i * sz, p2 + i * sz);
+            if (c)
+                return c;
+        }
+    }
+    if (a1.length == a2.length)
+        return 0;
+    return (a1.length > a2.length) ? 1 : -1;
+}
+
+extern (C) int _adCmp2(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    return ti.compare(&a1, &a2);
+}
+unittest
+{
+    debug(adi) printf("array.Cmp unittest\n");
+
+    auto a = "hello"c;
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
+
+/***************************************
+ * Support for array compare test.
+ */
+
+extern (C) int _adCmpChar(Array a1, Array a2)
+{
+  version (X86)
+  {
+    asm
+    {   naked                   ;
+
+        push    EDI             ;
+        push    ESI             ;
+
+        mov    ESI,a1+4[4+ESP]  ;
+        mov    EDI,a2+4[4+ESP]  ;
+
+        mov    ECX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+        cmp     ECX,EDX         ;
+        jb      GotLength       ;
+
+        mov     ECX,EDX         ;
+
+GotLength:
+        cmp    ECX,4            ;
+        jb    DoBytes           ;
+
+        // Do alignment if neither is dword aligned
+        test    ESI,3           ;
+        jz    Aligned           ;
+
+        test    EDI,3           ;
+        jz    Aligned           ;
+DoAlign:
+        mov    AL,[ESI]         ; //align ESI to dword bounds
+        mov    DL,[EDI]         ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        inc    ESI              ;
+        inc    EDI              ;
+
+        test    ESI,3           ;
+
+        lea    ECX,[ECX-1]      ;
+        jnz    DoAlign          ;
+Aligned:
+        mov    EAX,ECX          ;
+
+        // do multiple of 4 bytes at a time
+
+        shr    ECX,2            ;
+        jz    TryOdd            ;
+
+        repe                    ;
+        cmpsd                   ;
+
+        jnz    UnequalQuad      ;
+
+TryOdd:
+        mov    ECX,EAX          ;
+DoBytes:
+        // if still equal and not end of string, do up to 3 bytes slightly
+        // slower.
+
+        and    ECX,3            ;
+        jz    Equal             ;
+
+        repe                    ;
+        cmpsb                   ;
+
+        jnz    Unequal          ;
+Equal:
+        mov    EAX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+        sub    EAX,EDX          ;
+        pop    ESI              ;
+
+        pop    EDI              ;
+        ret                     ;
+
+UnequalQuad:
+        mov    EDX,[EDI-4]      ;
+        mov    EAX,[ESI-4]      ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        cmp    AH,DH            ;
+        jnz    Unequal          ;
+
+        shr    EAX,16           ;
+
+        shr    EDX,16           ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        cmp    AH,DH            ;
+Unequal:
+        sbb    EAX,EAX          ;
+        pop    ESI              ;
+
+        or     EAX,1            ;
+        pop    EDI              ;
+
+        ret                     ;
+    }
+  }
+  else
+  {
+    int len;
+    int c;
+
+    debug(adi) printf("adCmpChar()\n");
+    len = a1.length;
+    if (a2.length < len)
+        len = a2.length;
+    c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
+    if (!c)
+        c = cast(int)a1.length - cast(int)a2.length;
+    return c;
+  }
+}
+
+unittest
+{
+    debug(adi) printf("array.CmpChar unittest\n");
+
+    auto a = "hello"c;
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
Index: src/compiler/dmd/rt/lifetime.d
===================================================================
--- src/compiler/dmd/rt/lifetime.d	(revision 185)
+++ src/compiler/dmd/rt/lifetime.d	(working copy)
@@ -1,1075 +1,1074 @@
-/**
- * This module contains all functions related to an object's lifetime:
- * allocation, resizing, deallocation, and finalization.
- *
- * Copyright: Copyright Digital Mars 2000 - 2009.
- * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
- * Authors:   Walter Bright, Sean Kelly
- *
- *          Copyright Digital Mars 2000 - 2009.
- * Distributed under the Boost Software License, Version 1.0.
- *    (See accompanying file LICENSE_1_0.txt or copy at
- *          http://www.boost.org/LICENSE_1_0.txt)
- */
-module rt.lifetime;
-
-//debug=PRINTF;
-import core.stdc.stdio;
-
-private
-{
-    import core.stdc.stdlib;
-    import core.stdc.string;
-    import core.stdc.stdarg;
-    debug(PRINTF) import core.stdc.stdio;
-}
-
-
-private
-{
-    enum BlkAttr : uint
-    {
-        FINALIZE = 0b0000_0001,
-        NO_SCAN  = 0b0000_0010,
-        NO_MOVE  = 0b0000_0100,
-        ALL_BITS = 0b1111_1111
-    }
-
-    struct BlkInfo
-    {
-        void*  base;
-        size_t size;
-        uint   attr;
-    }
-
-    extern (C) uint gc_getAttr( void* p );
-    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) size_t gc_extend( void* p, size_t mx, size_t sz );
-    extern (C) void   gc_free( void* p );
-
-    extern (C) void*   gc_addrOf( void* p );
-    extern (C) size_t  gc_sizeOf( void* p );
-    extern (C) BlkInfo gc_query( void* p );
-
-    extern (C) void onFinalizeError( ClassInfo c, Throwable e );
-    extern (C) void onOutOfMemoryError();
-
-    extern (C) void _d_monitordelete(Object h, bool det = true);
-
-    enum
-    {
-        PAGESIZE = 4096
-    }
-
-    alias bool function(Object) CollectHandler;
-    __gshared CollectHandler collectHandler = null;
-}
-
-
-/**
- *
- */
-extern (C) void* _d_allocmemory(size_t sz)
-{
-    return gc_malloc(sz);
-}
-
-
-/**
- *
- */
-extern (C) Object _d_newclass(ClassInfo ci)
-{
-    void* p;
-
-    debug(PRINTF) printf("_d_newclass(ci = %p, %s)\n", ci, cast(char *)ci.name);
-    if (ci.flags & 1) // if COM object
-    {   /* COM objects are not garbage collected, they are reference counted
-         * using AddRef() and Release().  They get free'd by C's free()
-         * function called by Release() when Release()'s reference count goes
-         * to zero.
-     */
-        p = malloc(ci.init.length);
-        if (!p)
-            onOutOfMemoryError();
-    }
-    else
-    {
-        p = gc_malloc(ci.init.length,
-                      BlkAttr.FINALIZE | (ci.flags & 2 ? BlkAttr.NO_SCAN : 0));
-        debug(PRINTF) printf(" p = %p\n", p);
-    }
-
-    debug(PRINTF)
-    {
-        printf("p = %p\n", p);
-        printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length);
-        printf("vptr = %p\n", *cast(void**) ci.init);
-        printf("vtbl[0] = %p\n", (*cast(void***) ci.init)[0]);
-        printf("vtbl[1] = %p\n", (*cast(void***) ci.init)[1]);
-        printf("init[0] = %x\n", (cast(uint*) ci.init)[0]);
-        printf("init[1] = %x\n", (cast(uint*) ci.init)[1]);
-        printf("init[2] = %x\n", (cast(uint*) ci.init)[2]);
-        printf("init[3] = %x\n", (cast(uint*) ci.init)[3]);
-        printf("init[4] = %x\n", (cast(uint*) ci.init)[4]);
-    }
-
-    // initialize it
-    (cast(byte*) p)[0 .. ci.init.length] = ci.init[];
-
-    debug(PRINTF) printf("initialization done\n");
-    return cast(Object) p;
-}
-
-
-/**
- *
- */
-extern (C) void _d_delinterface(void** p)
-{
-    if (*p)
-    {
-        Interface* pi = **cast(Interface ***)*p;
-        Object     o  = cast(Object)(*p - pi.offset);
-
-        _d_delclass(&o);
-        *p = null;
-    }
-}
-
-
-// used for deletion
-private extern (D) alias void (*fp_t)(Object);
-
-
-/**
- *
- */
-extern (C) void _d_delclass(Object* p)
-{
-    if (*p)
-    {
-        debug(PRINTF) printf("_d_delclass(%p)\n", *p);
-
-        ClassInfo **pc = cast(ClassInfo **)*p;
-        if (*pc)
-        {
-            ClassInfo c = **pc;
-
-            rt_finalize(cast(void*) *p);
-
-            if (c.deallocator)
-            {
-                fp_t fp = cast(fp_t)c.deallocator;
-                (*fp)(*p); // call deallocator
-                *p = null;
-                return;
-            }
-        }
-        else
-        {
-            rt_finalize(cast(void*) *p);
-        }
-        gc_free(cast(void*) *p);
-        *p = null;
-    }
-}
-
-
-/**
- * Allocate a new array of length elements.
- * ti is the type of the resulting array, or pointer to element.
- * (For when the array is initialized to 0)
- */
-extern (C) ulong _d_newarrayT(TypeInfo ti, size_t length)
-{
-    void* p;
-    ulong result;
-    auto size = ti.next.tsize();                // array element size
-
-    debug(PRINTF) printf("_d_newarrayT(length = x%x, size = %d)\n", length, size);
-    if (length == 0 || size == 0)
-        result = 0;
-    else
-    {
-        version (D_InlineAsm_X86)
-        {
-            asm
-            {
-                mov     EAX,size        ;
-                mul     EAX,length      ;
-                mov     size,EAX        ;
-                jc      Loverflow       ;
-            }
-        }
-        else
-            size *= length;
-        p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
-        debug(PRINTF) printf(" p = %p\n", p);
-        memset(p, 0, size);
-        result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
-    }
-    return result;
-
-Loverflow:
-    onOutOfMemoryError();
-}
-
-/**
- * For when the array has a non-zero initializer.
- */
-extern (C) ulong _d_newarrayiT(TypeInfo ti, size_t length)
-{
-    ulong result;
-    auto size = ti.next.tsize();                // array element size
-
-    debug(PRINTF) printf("_d_newarrayiT(length = %d, size = %d)\n", length, size);
-
-    if (length == 0 || size == 0)
-        result = 0;
-    else
-    {
-        auto initializer = ti.next.init();
-        auto isize = initializer.length;
-        auto q = initializer.ptr;
-        version (D_InlineAsm_X86)
-        {
-            asm
-            {
-                mov     EAX,size        ;
-                mul     EAX,length      ;
-                mov     size,EAX        ;
-                jc      Loverflow       ;
-            }
-        }
-        else
-            size *= length;
-        auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
-        debug(PRINTF) printf(" p = %p\n", p);
-        if (isize == 1)
-            memset(p, *cast(ubyte*)q, size);
-        else if (isize == int.sizeof)
-        {
-            int init = *cast(int*)q;
-            size /= int.sizeof;
-            for (size_t u = 0; u < size; u++)
-            {
-                (cast(int*)p)[u] = init;
-            }
-        }
-        else
-        {
-            for (size_t u = 0; u < size; u += isize)
-            {
-                memcpy(p + u, q, isize);
-            }
-        }
-        va_end(q);
-        result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
-    }
-    return result;
-
-Loverflow:
-    onOutOfMemoryError();
-}
-
-/**
- *
- */
-extern (C) ulong _d_newarraymT(TypeInfo ti, int ndims, ...)
-{
-    ulong result;
-
-    debug(PRINTF) printf("_d_newarraymT(ndims = %d)\n", ndims);
-    if (ndims == 0)
-        result = 0;
-    else
-    {   va_list q;
-        va_start!(int)(q, ndims);
-
-        void[] foo(TypeInfo ti, size_t* pdim, int ndims)
-        {
-            size_t dim = *pdim;
-            void[] p;
-
-            debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims);
-            if (ndims == 1)
-            {
-                auto r = _d_newarrayT(ti, dim);
-                p = *cast(void[]*)(&r);
-            }
-            else
-            {
-                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
-                for (int i = 0; i < dim; i++)
-                {
-                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
-                }
-            }
-            return p;
-        }
-
-        size_t* pdim = cast(size_t *)q;
-        result = cast(ulong)foo(ti, pdim, ndims);
-        debug(PRINTF) printf("result = %llx\n", result);
-
-        version (none)
-        {
-            for (int i = 0; i < ndims; i++)
-            {
-                printf("index %d: %d\n", i, va_arg!(int)(q));
-            }
-        }
-        va_end(q);
-    }
-    return result;
-}
-
-
-/**
- *
- */
-extern (C) ulong _d_newarraymiT(TypeInfo ti, int ndims, ...)
-{
-    ulong result;
-
-    debug(PRINTF) printf("_d_newarraymiT(ndims = %d)\n", ndims);
-    if (ndims == 0)
-        result = 0;
-    else
-    {
-        va_list q;
-        va_start!(int)(q, ndims);
-
-        void[] foo(TypeInfo ti, size_t* pdim, int ndims)
-        {
-            size_t dim = *pdim;
-            void[] p;
-
-            if (ndims == 1)
-            {
-                auto r = _d_newarrayiT(ti, dim);
-                p = *cast(void[]*)(&r);
-            }
-            else
-            {
-                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
-                for (int i = 0; i < dim; i++)
-                {
-                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
-                }
-            }
-            return p;
-        }
-
-        size_t* pdim = cast(size_t *)q;
-        result = cast(ulong)foo(ti, pdim, ndims);
-        debug(PRINTF) printf("result = %llx\n", result);
-
-        version (none)
-        {
-            for (int i = 0; i < ndims; i++)
-            {
-                printf("index %d: %d\n", i, va_arg!(int)(q));
-                printf("init = %d\n", va_arg!(int)(q));
-            }
-        }
-        va_end(q);
-    }
-    return result;
-}
-
-
-/**
- *
- */
-struct Array
-{
-    size_t length;
-    byte*  data;
-}
-
-
-/**
- * This function has been replaced by _d_delarray_t
- */
-extern (C) void _d_delarray(Array *p)
-{
-    if (p)
-    {
-        assert(!p.length || p.data);
-
-        if (p.data)
-            gc_free(p.data);
-        p.data = null;
-        p.length = 0;
-    }
-}
-
-
-/**
- *
- */
-extern (C) void _d_delarray_t(Array *p, TypeInfo ti)
-{
-    if (p)
-    {
-        assert(!p.length || p.data);
-        if (p.data)
-        {
-            if (ti)
-            {
-                // Call destructors on all the sub-objects
-                auto sz = ti.tsize();
-                auto pe = p.data;
-                auto pend = pe + p.length * sz;
-                while (pe != pend)
-                {
-                    pend -= sz;
-                    ti.destroy(pend);
-                }
-            }
-            gc_free(p.data);
-        }
-        p.data = null;
-        p.length = 0;
-    }
-}
-
-
-/**
- *
- */
-extern (C) void _d_delmemory(void* *p)
-{
-    if (*p)
-    {
-        gc_free(*p);
-        *p = null;
-    }
-}
-
-
-/**
- *
- */
-extern (C) void _d_callinterfacefinalizer(void *p)
-{
-    if (p)
-    {
-        Interface *pi = **cast(Interface ***)p;
-        Object o = cast(Object)(p - pi.offset);
-        rt_finalize(cast(void*)o);
-    }
-}
-
-
-/**
- *
- */
-extern (C) void _d_callfinalizer(void* p)
-{
-    rt_finalize( p );
-}
-
-
-/**
- *
- */
-extern (C) void  rt_setCollectHandler(CollectHandler h)
-{
-    collectHandler = h;
-}
-
-
-/**
- *
- */
-extern (C) void rt_finalize(void* p, bool det = true)
-{
-    debug(PRINTF) printf("rt_finalize(p = %p)\n", p);
-
-    if (p) // not necessary if called from gc
-    {
-        ClassInfo** pc = cast(ClassInfo**)p;
-
-        if (*pc)
-        {
-            ClassInfo c = **pc;
-
-            try
-            {
-                if (det || collectHandler is null || collectHandler(cast(Object)p))
-                {
-                    do
-                    {
-                        if (c.destructor)
-                        {
-                            fp_t fp = cast(fp_t)c.destructor;
-                            (*fp)(cast(Object)p); // call destructor
-                        }
-                        c = c.base;
-                    } while (c);
-                }
-                if ((cast(void**)p)[1]) // if monitor is not null
-                    _d_monitordelete(cast(Object)p, det);
-            }
-            catch (Throwable e)
-            {
-                onFinalizeError(**pc, e);
-            }
-            finally
-            {
-                *pc = null; // zero vptr
-            }
-        }
-    }
-}
-
-
-/**
- * Resize dynamic arrays with 0 initializers.
- */
-extern (C) byte[] _d_arraysetlengthT(TypeInfo ti, size_t newlength, Array *p)
-in
-{
-    assert(ti);
-    assert(!p.length || p.data);
-}
-body
-{
-    debug(PRINTF)
-    {
-        //printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
-        if (p)
-            printf("\tp.data = %p, p.length = %d\n", p.data, p.length);
-    }
-
-    byte* newdata = void;
-    if (newlength)
-    {
-        if (newlength <= p.length)
-        {
-            p.length = newlength;
-            newdata = p.data;
-            return newdata[0 .. newlength];
-        }
-        size_t sizeelem = ti.next.tsize();
-        version (D_InlineAsm_X86)
-        {
-            size_t newsize = void;
-
-            asm
-            {
-                mov EAX, newlength;
-                mul EAX, sizeelem;
-                mov newsize, EAX;
-                jc  Loverflow;
-            }
-        }
-        else
-        {
-            size_t newsize = sizeelem * newlength;
-
-            if (newsize / newlength != sizeelem)
-                goto Loverflow;
-        }
-
-        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
-
-        if (p.data)
-        {
-            newdata = p.data;
-            if (newlength > p.length)
-            {
-                size_t size = p.length * sizeelem;
-                auto   info = gc_query(p.data);
-
-                if (info.size <= newsize || info.base != p.data)
-                {
-                    if (info.size >= PAGESIZE && info.base == p.data)
-                    {   // Try to extend in-place
-                        auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
-                        if (u)
-                        {
-                            goto L1;
-                        }
-                    }
-                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
-                    newdata[0 .. size] = p.data[0 .. size];
-                }
-             L1:
-                newdata[size .. newsize] = 0;
-            }
-        }
-        else
-        {
-            newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
-        }
-    }
-    else
-    {
-        newdata = p.data;
-    }
-
-    p.data = newdata;
-    p.length = newlength;
-    return newdata[0 .. newlength];
-
-Loverflow:
-    onOutOfMemoryError();
-}
-
-
-/**
- * Resize arrays for non-zero initializers.
- *      p               pointer to array lvalue to be updated
- *      newlength       new .length property of array
- *      sizeelem        size of each element of array
- *      initsize        size of initializer
- *      ...             initializer
- */
-extern (C) byte[] _d_arraysetlengthiT(TypeInfo ti, size_t newlength, Array *p)
-in
-{
-    assert(!p.length || p.data);
-}
-body
-{
-    byte* newdata;
-    size_t sizeelem = ti.next.tsize();
-    void[] initializer = ti.next.init();
-    size_t initsize = initializer.length;
-
-    assert(sizeelem);
-    assert(initsize);
-    assert(initsize <= sizeelem);
-    assert((sizeelem / initsize) * initsize == sizeelem);
-
-    debug(PRINTF)
-    {
-        printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d)\n", p, sizeelem, newlength, initsize);
-        if (p)
-            printf("\tp.data = %p, p.length = %d\n", p.data, p.length);
-    }
-
-    if (newlength)
-    {
-        version (D_InlineAsm_X86)
-        {
-            size_t newsize = void;
-
-            asm
-            {
-                mov     EAX,newlength   ;
-                mul     EAX,sizeelem    ;
-                mov     newsize,EAX     ;
-                jc      Loverflow       ;
-            }
-        }
-        else
-        {
-            size_t newsize = sizeelem * newlength;
-
-            if (newsize / newlength != sizeelem)
-                goto Loverflow;
-        }
-        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
-
-        size_t size = p.length * sizeelem;
-
-        if (p.data)
-        {
-            newdata = p.data;
-            if (newlength > p.length)
-            {
-                auto info = gc_query(p.data);
-
-                if (info.size <= newsize || info.base != p.data)
-                {
-                    if (info.size >= PAGESIZE && info.base == p.data)
-                    {   // Try to extend in-place
-                        auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
-                        if (u)
-                        {
-                            goto L1;
-                        }
-                    }
-                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
-                    newdata[0 .. size] = p.data[0 .. size];
-                L1: ;
-                }
-            }
-        }
-        else
-        {
-            newdata = cast(byte *)gc_malloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
-        }
-
-        auto q = initializer.ptr; // pointer to initializer
-
-        if (newsize > size)
-        {
-            if (initsize == 1)
-            {
-                debug(PRINTF) printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q);
-                newdata[size .. newsize] = *(cast(byte*)q);
-            }
-            else
-            {
-                for (size_t u = size; u < newsize; u += initsize)
-                {
-                    memcpy(newdata + u, q, initsize);
-                }
-            }
-        }
-    }
-    else
-    {
-        newdata = p.data;
-    }
-
-    p.data = newdata;
-    p.length = newlength;
-    return newdata[0 .. newlength];
-
-Loverflow:
-    onOutOfMemoryError();
-}
-
-
-/**
- * Append y[] to array x[].
- * size is size of each array element.
- */
-extern (C) long _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)
-{
-    auto sizeelem = ti.next.tsize();            // array element size
-    auto info = gc_query(px.data);
-    auto length = px.length;
-    auto newlength = length + y.length;
-    auto newsize = newlength * sizeelem;
-
-    if (info.size < newsize || info.base != px.data)
-    {   byte* newdata;
-
-        if (info.size >= PAGESIZE && info.base == px.data)
-        {   // Try to extend in-place
-            auto u = gc_extend(px.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
-            if (u)
-            {
-                goto L1;
-            }
-        }
-        newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr);
-        memcpy(newdata, px.data, length * sizeelem);
-        px.data = newdata;
-    }
-  L1:
-    px.length = newlength;
-    memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem);
-    return *cast(long*)px;
-}
-
-
-/**
- *
- */
-size_t newCapacity(size_t newlength, size_t size)
-{
-    version(none)
-    {
-        size_t newcap = newlength * size;
-    }
-    else
-    {
-        /*
-         * Better version by Dave Fladebo:
-         * This uses an inverse logorithmic algorithm to pre-allocate a bit more
-         * space for larger arrays.
-         * - Arrays smaller than PAGESIZE bytes are left as-is, so for the most
-         * common cases, memory allocation is 1 to 1. The small overhead added
-         * doesn't affect small array perf. (it's virtually the same as
-         * current).
-         * - Larger arrays have some space pre-allocated.
-         * - As the arrays grow, the relative pre-allocated space shrinks.
-         * - The logorithmic algorithm allocates relatively more space for
-         * mid-size arrays, making it very fast for medium arrays (for
-         * mid-to-large arrays, this turns out to be quite a bit faster than the
-         * equivalent realloc() code in C, on Linux at least. Small arrays are
-         * just as fast as GCC).
-         * - Perhaps most importantly, overall memory usage and stress on the GC
-         * is decreased significantly for demanding environments.
-         */
-        size_t newcap = newlength * size;
-        size_t newext = 0;
-
-        if (newcap > PAGESIZE)
-        {
-            //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0)));
-
-            // redo above line using only integer math
-
-            static int log2plus1(size_t c)
-            {   int i;
-
-                if (c == 0)
-                    i = -1;
-                else
-                    for (i = 1; c >>= 1; i++)
-                    {
-                    }
-                return i;
-            }
-
-            /* The following setting for mult sets how much bigger
-             * the new size will be over what is actually needed.
-             * 100 means the same size, more means proportionally more.
-             * More means faster but more memory consumption.
-             */
-            //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap));
-            long mult = 100 + (1000L * size) / log2plus1(newcap);
-
-            // testing shows 1.02 for large arrays is about the point of diminishing return
-            if (mult < 102)
-                mult = 102;
-            newext = cast(size_t)((newcap * mult) / 100);
-            newext -= newext % size;
-            debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/100.0,newext / cast(double)size);
-        }
-        newcap = newext > newcap ? newext : newcap;
-        debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size);
-    }
-    return newcap;
-}
-
-
-/**
- *
- */
-extern (C) byte[] _d_arrayappendcT(TypeInfo ti, inout byte[] x, ...)
-{
-    auto sizeelem = ti.next.tsize();            // array element size
-    auto info = gc_query(x.ptr);
-    auto length = x.length;
-    auto newlength = length + 1;
-    auto newsize = newlength * sizeelem;
-
-    assert(info.size == 0 || length * sizeelem <= info.size);
-
-    debug(PRINTF) printf("_d_arrayappendcT(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size);
-
-    if (info.size <= newsize || info.base != x.ptr)
-    {   byte* newdata;
-
-        if (info.size >= PAGESIZE && info.base == x.ptr)
-        {   // Try to extend in-place
-            auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size);
-            if (u)
-            {
-                goto L1;
-            }
-        }
-        debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size);
-        auto newcap = newCapacity(newlength, sizeelem);
-        assert(newcap >= newlength * sizeelem);
-        newdata = cast(byte *)gc_malloc(newcap + 1, info.attr);
-        memcpy(newdata, x.ptr, length * sizeelem);
-        (cast(void**)(&x))[1] = newdata;
-    }
-  L1:
-    byte *argp = cast(byte *)(&ti + 2);
-
-    *cast(size_t *)&x = newlength;
-    x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
-    assert((cast(size_t)x.ptr & 15) == 0);
-    assert(gc_sizeOf(x.ptr) > x.length * sizeelem);
-    return x;
-}
-
-
-/**
- *
- */
-extern (C) byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y)
-out (result)
-{
-    auto sizeelem = ti.next.tsize();            // array element size
-    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr);
-    assert(result.length == x.length + y.length);
-    for (size_t i = 0; i < x.length * sizeelem; i++)
-        assert((cast(byte*)result)[i] == (cast(byte*)x)[i]);
-    for (size_t i = 0; i < y.length * sizeelem; i++)
-        assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]);
-
-    size_t cap = gc_sizeOf(result.ptr);
-    assert(!cap || cap > result.length * sizeelem);
-}
-body
-{
-    version (none)
-    {
-        /* Cannot use this optimization because:
-         *  char[] a, b;
-         *  char c = 'a';
-         *  b = a ~ c;
-         *  c = 'b';
-         * will change the contents of b.
-         */
-        if (!y.length)
-            return x;
-        if (!x.length)
-            return y;
-    }
-
-    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr);
-    auto sizeelem = ti.next.tsize();            // array element size
-    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem);
-    size_t xlen = x.length * sizeelem;
-    size_t ylen = y.length * sizeelem;
-    size_t len  = xlen + ylen;
-
-    if (!len)
-        return null;
-
-    byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
-    memcpy(p, x.ptr, xlen);
-    memcpy(p + xlen, y.ptr, ylen);
-    p[len] = 0;
-    return p[0 .. x.length + y.length];
-}
-
-
-/**
- *
- */
-extern (C) byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
-{   void* a;
-    size_t length;
-    byte[]* p;
-    uint i;
-    byte[] b;
-    auto size = ti.next.tsize(); // array element size
-
-    p = cast(byte[]*)(&n + 1);
-
-    for (i = 0; i < n; i++)
-    {
-        b = *p++;
-        length += b.length;
-    }
-    if (!length)
-        return null;
-
-    a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
-    p = cast(byte[]*)(&n + 1);
-
-    uint j = 0;
-    for (i = 0; i < n; i++)
-    {
-        b = *p++;
-        if (b.length)
-        {
-            memcpy(a + j, b.ptr, b.length * size);
-            j += b.length * size;
-        }
-    }
-
-    byte[] result;
-    *cast(int *)&result = length;       // jam length
-    (cast(void **)&result)[1] = a;      // jam ptr
-    return result;
-}
-
-
-/**
- *
- */
-extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...)
-{
-    auto sizeelem = ti.next.tsize();            // array element size
-    void* result;
-
-    debug(PRINTF) printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length);
-    if (length == 0 || sizeelem == 0)
-        result = null;
-    else
-    {
-        result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
-
-        va_list q;
-        va_start!(size_t)(q, length);
-
-        size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1);
-
-        if (stacksize == sizeelem)
-        {
-            memcpy(result, q, length * sizeelem);
-        }
-        else
-        {
-            for (size_t i = 0; i < length; i++)
-            {
-                memcpy(result + i * sizeelem, q, sizeelem);
-                q += stacksize;
-            }
-        }
-
-        va_end(q);
-    }
-    return result;
-}
-
-
-/**
- * Support for array.dup property.
- */
-struct Array2
-{
-    size_t length;
-    void*  ptr;
-}
-
-
-/**
- *
- */
-extern (C) long _adDupT(TypeInfo ti, Array2 a)
-out (result)
-{
-    auto sizeelem = ti.next.tsize();            // array element size
-    assert(memcmp((*cast(Array2*)&result).ptr, a.ptr, a.length * sizeelem) == 0);
-}
-body
-{
-    Array2 r;
-
-    if (a.length)
-    {
-        auto sizeelem = ti.next.tsize();                // array element size
-        auto size = a.length * sizeelem;
-        r.ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
-        r.length = a.length;
-        memcpy(r.ptr, a.ptr, size);
-    }
-    return *cast(long*)(&r);
-}
-
-
-unittest
-{
-    int[] a;
-    int[] b;
-    int i;
-
-    a = new int[3];
-    a[0] = 1; a[1] = 2; a[2] = 3;
-    b = a.dup;
-    assert(b.length == 3);
-    for (i = 0; i < 3; i++)
-        assert(b[i] == i + 1);
-}
+/**
+ * This module contains all functions related to an object's lifetime:
+ * allocation, resizing, deallocation, and finalization.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.lifetime;
+
+
+private
+{
+    import core.stdc.stdlib;
+    import core.stdc.string;
+    import core.stdc.stdarg;
+    debug(PRINTF) import core.stdc.stdio;
+    __gshared size_t[3] conservativeBitMask = [3, 1, 0];
+}
+
+
+private
+{
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    struct BlkInfo
+    {
+        void*  base;
+        size_t size;
+        uint   attr;
+    }
+
+    extern (C) uint gc_getAttr( void* p );
+    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, 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 );
+
+    extern (C) void*   gc_addrOf( void* p );
+    extern (C) size_t  gc_sizeOf( void* p );
+    extern (C) BlkInfo gc_query( void* p );
+
+    extern (C) void onFinalizeError( ClassInfo c, Throwable e );
+    extern (C) void onOutOfMemoryError();
+
+    extern (C) void _d_monitordelete(Object h, bool det = true);
+
+    enum
+    {
+        PAGESIZE = 4096
+    }
+
+    alias bool function(Object) CollectHandler;
+    __gshared CollectHandler collectHandler = null;
+}
+
+
+/**
+ *
+ */
+extern (C) void* _d_allocmemory(size_t sz)
+{
+    return gc_malloc(sz);
+}
+
+
+/**
+ *
+ */
+extern (C) Object _d_newclass(ClassInfo ci)
+{
+    void* p;
+
+    debug(PRINTF) printf("_d_newclass(ci = %p, %s)\n", ci, cast(char *)ci.name);
+    if (ci.flags & 1) // if COM object
+    {   /* COM objects are not garbage collected, they are reference counted
+         * using AddRef() and Release().  They get free'd by C's free()
+         * function called by Release() when Release()'s reference count goes
+         * to zero.
+     */
+        p = malloc(ci.init.length);
+        if (!p)
+            onOutOfMemoryError();
+    }
+    else
+    {
+        p = gc_malloc(ci.init.length,
+                      BlkAttr.FINALIZE | (ci.flags & 2 ? BlkAttr.NO_SCAN : 0));
+        debug(PRINTF) printf(" p = %p\n", p);
+    }
+
+    debug(PRINTF)
+    {
+        printf("p = %p\n", p);
+        printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length);
+        printf("vptr = %p\n", *cast(void**) ci.init);
+        printf("vtbl[0] = %p\n", (*cast(void***) ci.init)[0]);
+        printf("vtbl[1] = %p\n", (*cast(void***) ci.init)[1]);
+        printf("init[0] = %x\n", (cast(uint*) ci.init)[0]);
+        printf("init[1] = %x\n", (cast(uint*) ci.init)[1]);
+        printf("init[2] = %x\n", (cast(uint*) ci.init)[2]);
+        printf("init[3] = %x\n", (cast(uint*) ci.init)[3]);
+        printf("init[4] = %x\n", (cast(uint*) ci.init)[4]);
+    }
+
+    // initialize it
+    (cast(byte*) p)[0 .. ci.init.length] = ci.init[];
+
+    debug(PRINTF) printf("initialization done\n");
+    return cast(Object) p;
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_delinterface(void** p)
+{
+    if (*p)
+    {
+        Interface* pi = **cast(Interface ***)*p;
+        Object     o  = cast(Object)(*p - pi.offset);
+
+        _d_delclass(&o);
+        *p = null;
+    }
+}
+
+
+// used for deletion
+private extern (D) alias void (*fp_t)(Object);
+
+
+/**
+ *
+ */
+extern (C) void _d_delclass(Object* p)
+{
+    if (*p)
+    {
+        debug(PRINTF) printf("_d_delclass(%p)\n", *p);
+
+        ClassInfo **pc = cast(ClassInfo **)*p;
+        if (*pc)
+        {
+            ClassInfo c = **pc;
+
+            rt_finalize(cast(void*) *p);
+
+            if (c.deallocator)
+            {
+                fp_t fp = cast(fp_t)c.deallocator;
+                (*fp)(*p); // call deallocator
+                *p = null;
+                return;
+            }
+        }
+        else
+        {
+            rt_finalize(cast(void*) *p);
+        }
+        gc_free(cast(void*) *p);
+        *p = null;
+    }
+}
+
+
+/**
+ * Allocate a new array of length elements.
+ * ti is the type of the resulting array, or pointer to element.
+ * (For when the array is initialized to 0)
+ */
+extern (C) ulong _d_newarrayT(TypeInfo ti, size_t length)
+{
+    void* p;
+    ulong result;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayT(length = x%x, size = %d)\n", length, size);
+    if (length == 0 || size == 0)
+        result = 0;
+    else
+    {
+        version (D_InlineAsm_X86)
+        {
+            asm
+            {
+                mov     EAX,size        ;
+                mul     EAX,length      ;
+                mov     size,EAX        ;
+                jc      Loverflow       ;
+            }
+        }
+        else
+            size *= length;
+        p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        debug(PRINTF) printf(" p = %p\n", p);
+        memset(p, 0, size);
+        result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
+    }
+    return result;
+
+Loverflow:
+    onOutOfMemoryError();
+}
+
+/**
+ * For when the array has a non-zero initializer.
+ */
+extern (C) ulong _d_newarrayiT(TypeInfo ti, size_t length)
+{
+    ulong result;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayiT(length = %d, size = %d)\n", length, size);
+
+    if (length == 0 || size == 0)
+        result = 0;
+    else
+    {
+        auto initializer = ti.next.init();
+        auto isize = initializer.length;
+        auto q = initializer.ptr;
+        version (D_InlineAsm_X86)
+        {
+            asm
+            {
+                mov     EAX,size        ;
+                mul     EAX,length      ;
+                mov     size,EAX        ;
+                jc      Loverflow       ;
+            }
+        }
+        else
+            size *= length;
+        auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        debug(PRINTF) printf(" p = %p\n", p);
+        if (isize == 1)
+            memset(p, *cast(ubyte*)q, size);
+        else if (isize == int.sizeof)
+        {
+            int init = *cast(int*)q;
+            size /= int.sizeof;
+            for (size_t u = 0; u < size; u++)
+            {
+                (cast(int*)p)[u] = init;
+            }
+        }
+        else
+        {
+            for (size_t u = 0; u < size; u += isize)
+            {
+                memcpy(p + u, q, isize);
+            }
+        }
+        va_end(q);
+        result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
+    }
+    return result;
+
+Loverflow:
+    onOutOfMemoryError();
+}
+
+/**
+ *
+ */
+extern (C) ulong _d_newarraymT(TypeInfo ti, int ndims, ...)
+{
+    ulong result;
+
+    debug(PRINTF) printf("_d_newarraymT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+        result = 0;
+    else
+    {   va_list q;
+        va_start!(int)(q, ndims);
+
+        void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+        {
+            size_t dim = *pdim;
+            void[] p;
+
+            debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims);
+            if (ndims == 1)
+            {
+                auto r = _d_newarrayT(ti, dim);
+                p = *cast(void[]*)(&r);
+            }
+            else
+            {
+                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+                for (int i = 0; i < dim; i++)
+                {
+                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+                }
+            }
+            return p;
+        }
+
+        size_t* pdim = cast(size_t *)q;
+        result = cast(ulong)foo(ti, pdim, ndims);
+        debug(PRINTF) printf("result = %llx\n", result);
+
+        version (none)
+        {
+            for (int i = 0; i < ndims; i++)
+            {
+                printf("index %d: %d\n", i, va_arg!(int)(q));
+            }
+        }
+        va_end(q);
+    }
+    return result;
+}
+
+
+/**
+ *
+ */
+extern (C) ulong _d_newarraymiT(TypeInfo ti, int ndims, ...)
+{
+    ulong result;
+
+    debug(PRINTF) printf("_d_newarraymiT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+        result = 0;
+    else
+    {
+        va_list q;
+        va_start!(int)(q, ndims);
+
+        void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+        {
+            size_t dim = *pdim;
+            void[] p;
+
+            if (ndims == 1)
+            {
+                auto r = _d_newarrayiT(ti, dim);
+                p = *cast(void[]*)(&r);
+            }
+            else
+            {
+                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+                for (int i = 0; i < dim; i++)
+                {
+                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+                }
+            }
+            return p;
+        }
+
+        size_t* pdim = cast(size_t *)q;
+        result = cast(ulong)foo(ti, pdim, ndims);
+        debug(PRINTF) printf("result = %llx\n", result);
+
+        version (none)
+        {
+            for (int i = 0; i < ndims; i++)
+            {
+                printf("index %d: %d\n", i, va_arg!(int)(q));
+                printf("init = %d\n", va_arg!(int)(q));
+            }
+        }
+        va_end(q);
+    }
+    return result;
+}
+
+
+/**
+ *
+ */
+struct Array
+{
+    size_t length;
+    byte*  data;
+}
+
+
+/**
+ * This function has been replaced by _d_delarray_t
+ */
+extern (C) void _d_delarray(Array *p)
+{
+    if (p)
+    {
+        assert(!p.length || p.data);
+
+        if (p.data)
+            gc_free(p.data);
+        p.data = null;
+        p.length = 0;
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_delarray_t(Array *p, TypeInfo ti)
+{
+    if (p)
+    {
+        assert(!p.length || p.data);
+        if (p.data)
+        {
+            if (ti)
+            {
+                // Call destructors on all the sub-objects
+                auto sz = ti.tsize();
+                auto pe = p.data;
+                auto pend = pe + p.length * sz;
+                while (pe != pend)
+                {
+                    pend -= sz;
+                    ti.destroy(pend);
+                }
+            }
+            gc_free(p.data);
+        }
+        p.data = null;
+        p.length = 0;
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_delmemory(void* *p)
+{
+    if (*p)
+    {
+        gc_free(*p);
+        *p = null;
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_callinterfacefinalizer(void *p)
+{
+    if (p)
+    {
+        Interface *pi = **cast(Interface ***)p;
+        Object o = cast(Object)(p - pi.offset);
+        rt_finalize(cast(void*)o);
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_callfinalizer(void* p)
+{
+    rt_finalize( p );
+}
+
+
+/**
+ *
+ */
+extern (C) void  rt_setCollectHandler(CollectHandler h)
+{
+    collectHandler = h;
+}
+
+
+/**
+ *
+ */
+extern (C) void rt_finalize(void* p, bool det = true)
+{
+    debug(PRINTF) printf("rt_finalize(p = %p)\n", p);
+
+    if (p) // not necessary if called from gc
+    {
+        ClassInfo** pc = cast(ClassInfo**)p;
+
+        if (*pc)
+        {
+            ClassInfo c = **pc;
+
+            try
+            {
+                if (det || collectHandler is null || collectHandler(cast(Object)p))
+                {
+                    do
+                    {
+                        if (c.destructor)
+                        {
+                            fp_t fp = cast(fp_t)c.destructor;
+                            (*fp)(cast(Object)p); // call destructor
+                        }
+                        c = c.base;
+                    } while (c);
+                }
+                if ((cast(void**)p)[1]) // if monitor is not null
+                    _d_monitordelete(cast(Object)p, det);
+            }
+            catch (Throwable e)
+            {
+                onFinalizeError(**pc, e);
+            }
+            finally
+            {
+                *pc = null; // zero vptr
+            }
+        }
+    }
+}
+
+
+/**
+ * Resize dynamic arrays with 0 initializers.
+ */
+extern (C) byte[] _d_arraysetlengthT(TypeInfo ti, size_t newlength, Array *p)
+in
+{
+    assert(ti);
+    assert(!p.length || p.data);
+}
+body
+{
+    debug(PRINTF)
+    {
+        printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
+        if (p)
+            printf("\tp.data = %p, p.length = %d\n", p.data, p.length);
+    }
+
+    byte* newdata = void;
+    if (newlength)
+    {
+        if (newlength <= p.length)
+        {
+            p.length = newlength;
+            newdata = p.data;
+            return newdata[0 .. newlength];
+        }
+        size_t sizeelem = ti.next.tsize();
+        version (D_InlineAsm_X86)
+        {
+            size_t newsize = void;
+
+            asm
+            {
+                mov EAX, newlength;
+                mul EAX, sizeelem;
+                mov newsize, EAX;
+                jc  Loverflow;
+            }
+        }
+        else
+        {
+            size_t newsize = sizeelem * newlength;
+
+            if (newsize / newlength != sizeelem)
+                goto Loverflow;
+        }
+
+        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+        if (p.data)
+        {
+            newdata = p.data;
+            if (newlength > p.length)
+            {
+                size_t size = p.length * sizeelem;
+                auto   info = gc_query(p.data);
+
+                if (info.size <= newsize || info.base != p.data)
+                {
+                    if (info.size >= PAGESIZE && info.base == p.data)
+                    {   // Try to extend in-place
+                        auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+                        if (u)
+                        {
+                            goto L1;
+                        }
+                    }
+                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
+                    newdata[0 .. size] = p.data[0 .. size];
+                }
+             L1:
+                newdata[size .. newsize] = 0;
+            }
+        }
+        else
+        {
+            newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        }
+    }
+    else
+    {
+        newdata = p.data;
+    }
+
+    p.data = newdata;
+    p.length = newlength;
+    return newdata[0 .. newlength];
+
+Loverflow:
+    onOutOfMemoryError();
+}
+
+
+/**
+ * Resize arrays for non-zero initializers.
+ *      p               pointer to array lvalue to be updated
+ *      newlength       new .length property of array
+ *      sizeelem        size of each element of array
+ *      initsize        size of initializer
+ *      ...             initializer
+ */
+extern (C) byte[] _d_arraysetlengthiT(TypeInfo ti, size_t newlength, Array *p)
+in
+{
+    assert(!p.length || p.data);
+}
+body
+{
+    byte* newdata;
+    size_t sizeelem = ti.next.tsize();
+    void[] initializer = ti.next.init();
+    size_t initsize = initializer.length;
+
+    assert(sizeelem);
+    assert(initsize);
+    assert(initsize <= sizeelem);
+    assert((sizeelem / initsize) * initsize == sizeelem);
+
+    debug(PRINTF)
+    {
+        printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d)\n", p, sizeelem, newlength, initsize);
+        if (p)
+            printf("\tp.data = %p, p.length = %d\n", p.data, p.length);
+    }
+
+    if (newlength)
+    {
+        version (D_InlineAsm_X86)
+        {
+            size_t newsize = void;
+
+            asm
+            {
+                mov     EAX,newlength   ;
+                mul     EAX,sizeelem    ;
+                mov     newsize,EAX     ;
+                jc      Loverflow       ;
+            }
+        }
+        else
+        {
+            size_t newsize = sizeelem * newlength;
+
+            if (newsize / newlength != sizeelem)
+                goto Loverflow;
+        }
+        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+        size_t size = p.length * sizeelem;
+
+        if (p.data)
+        {
+            newdata = p.data;
+            if (newlength > p.length)
+            {
+                auto info = gc_query(p.data);
+
+                if (info.size <= newsize || info.base != p.data)
+                {
+                    if (info.size >= PAGESIZE && info.base == p.data)
+                    {   // Try to extend in-place
+                        auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+                        if (u)
+                        {
+                            goto L1;
+                        }
+                    }
+                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
+                    newdata[0 .. size] = p.data[0 .. size];
+                L1: ;
+                }
+            }
+        }
+        else
+        {
+            newdata = cast(byte *)gc_malloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        }
+
+        auto q = initializer.ptr; // pointer to initializer
+
+        if (newsize > size)
+        {
+            if (initsize == 1)
+            {
+                debug(PRINTF) printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q);
+                newdata[size .. newsize] = *(cast(byte*)q);
+            }
+            else
+            {
+                for (size_t u = size; u < newsize; u += initsize)
+                {
+                    memcpy(newdata + u, q, initsize);
+                }
+            }
+        }
+    }
+    else
+    {
+        newdata = p.data;
+    }
+
+    p.data = newdata;
+    p.length = newlength;
+    return newdata[0 .. newlength];
+
+Loverflow:
+    onOutOfMemoryError();
+}
+
+
+/**
+ * Append y[] to array x[].
+ * size is size of each array element.
+ */
+extern (C) long _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    auto info = gc_query(px.data);
+    auto length = px.length;
+    auto newlength = length + y.length;
+    auto newsize = newlength * sizeelem;
+
+    if (info.size < newsize || info.base != px.data)
+    {   byte* newdata;
+
+        if (info.size >= PAGESIZE && info.base == px.data)
+        {   // Try to extend in-place
+            auto u = gc_extend(px.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+            if (u)
+            {
+                goto L1;
+            }
+        }
+        newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr);
+        memcpy(newdata, px.data, length * sizeelem);
+        px.data = newdata;
+    }
+  L1:
+    px.length = newlength;
+    memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem);
+    return *cast(long*)px;
+}
+
+
+/**
+ *
+ */
+size_t newCapacity(size_t newlength, size_t size)
+{
+    version(none)
+    {
+        size_t newcap = newlength * size;
+    }
+    else
+    {
+        /*
+         * Better version by Dave Fladebo:
+         * This uses an inverse logorithmic algorithm to pre-allocate a bit more
+         * space for larger arrays.
+         * - Arrays smaller than PAGESIZE bytes are left as-is, so for the most
+         * common cases, memory allocation is 1 to 1. The small overhead added
+         * doesn't affect small array perf. (it's virtually the same as
+         * current).
+         * - Larger arrays have some space pre-allocated.
+         * - As the arrays grow, the relative pre-allocated space shrinks.
+         * - The logorithmic algorithm allocates relatively more space for
+         * mid-size arrays, making it very fast for medium arrays (for
+         * mid-to-large arrays, this turns out to be quite a bit faster than the
+         * equivalent realloc() code in C, on Linux at least. Small arrays are
+         * just as fast as GCC).
+         * - Perhaps most importantly, overall memory usage and stress on the GC
+         * is decreased significantly for demanding environments.
+         */
+        size_t newcap = newlength * size;
+        size_t newext = 0;
+
+        if (newcap > PAGESIZE)
+        {
+            //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0)));
+
+            // redo above line using only integer math
+
+            static int log2plus1(size_t c)
+            {   int i;
+
+                if (c == 0)
+                    i = -1;
+                else
+                    for (i = 1; c >>= 1; i++)
+                    {
+                    }
+                return i;
+            }
+
+            /* The following setting for mult sets how much bigger
+             * the new size will be over what is actually needed.
+             * 100 means the same size, more means proportionally more.
+             * More means faster but more memory consumption.
+             */
+            //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap));
+            long mult = 100 + (1000L * size) / log2plus1(newcap);
+
+            // testing shows 1.02 for large arrays is about the point of diminishing return
+            if (mult < 102)
+                mult = 102;
+            newext = cast(size_t)((newcap * mult) / 100);
+            newext -= newext % size;
+            debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/100.0,newext / cast(double)size);
+        }
+        newcap = newext > newcap ? newext : newcap;
+        debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size);
+    }
+    return newcap;
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arrayappendcT(TypeInfo ti, inout byte[] x, ...)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    auto info = gc_query(x.ptr);
+    auto length = x.length;
+    auto newlength = length + 1;
+    auto newsize = newlength * sizeelem;
+
+    assert(info.size == 0 || length * sizeelem <= info.size);
+
+    debug(PRINTF) printf("_d_arrayappendcT(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size);
+
+    if (info.size <= newsize || info.base != x.ptr)
+    {   byte* newdata;
+
+        if (info.size >= PAGESIZE && info.base == x.ptr)
+        {   // Try to extend in-place
+            auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size);
+            if (u)
+            {
+                goto L1;
+            }
+        }
+        debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size);
+        auto newcap = newCapacity(newlength, sizeelem);
+        assert(newcap >= newlength * sizeelem);
+        newdata = cast(byte *)gc_malloc(newcap + 1, info.attr);
+        memcpy(newdata, x.ptr, length * sizeelem);
+        (cast(void**)(&x))[1] = newdata;
+    }
+  L1:
+    byte *argp = cast(byte *)(&ti + 2);
+
+    *cast(size_t *)&x = newlength;
+    x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
+    assert((cast(size_t)x.ptr & 15) == 0);
+    assert(gc_sizeOf(x.ptr) > x.length * sizeelem);
+    return x;
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y)
+out (result)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr);
+    assert(result.length == x.length + y.length);
+    for (size_t i = 0; i < x.length * sizeelem; i++)
+        assert((cast(byte*)result)[i] == (cast(byte*)x)[i]);
+    for (size_t i = 0; i < y.length * sizeelem; i++)
+        assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]);
+
+    size_t cap = gc_sizeOf(result.ptr);
+    assert(!cap || cap > result.length * sizeelem);
+}
+body
+{
+    version (none)
+    {
+        /* Cannot use this optimization because:
+         *  char[] a, b;
+         *  char c = 'a';
+         *  b = a ~ c;
+         *  c = 'b';
+         * will change the contents of b.
+         */
+        if (!y.length)
+            return x;
+        if (!x.length)
+            return y;
+    }
+
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr);
+    auto sizeelem = ti.next.tsize();            // array element size
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem);
+    size_t xlen = x.length * sizeelem;
+    size_t ylen = y.length * sizeelem;
+    size_t len  = xlen + ylen;
+
+    if (!len)
+        return null;
+
+    byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    memcpy(p, x.ptr, xlen);
+    memcpy(p + xlen, y.ptr, ylen);
+    p[len] = 0;
+    return p[0 .. x.length + y.length];
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
+{   void* a;
+    size_t length;
+    byte[]* p;
+    uint i;
+    byte[] b;
+    auto size = ti.next.tsize(); // array element size
+
+    p = cast(byte[]*)(&n + 1);
+
+    for (i = 0; i < n; i++)
+    {
+        b = *p++;
+        length += b.length;
+    }
+    if (!length)
+        return null;
+
+    a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    p = cast(byte[]*)(&n + 1);
+
+    uint j = 0;
+    for (i = 0; i < n; i++)
+    {
+        b = *p++;
+        if (b.length)
+        {
+            memcpy(a + j, b.ptr, b.length * size);
+            j += b.length * size;
+        }
+    }
+
+    byte[] result;
+    *cast(int *)&result = length;       // jam length
+    (cast(void **)&result)[1] = a;      // jam ptr
+    return result;
+}
+
+
+/**
+ *
+ */
+extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    void* result;
+
+    debug(PRINTF) printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length);
+    if (length == 0 || sizeelem == 0)
+        result = null;
+    else
+    {
+        result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+
+        va_list q;
+        va_start!(size_t)(q, length);
+
+        size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1);
+
+        if (stacksize == sizeelem)
+        {
+            memcpy(result, q, length * sizeelem);
+        }
+        else
+        {
+            for (size_t i = 0; i < length; i++)
+            {
+                memcpy(result + i * sizeelem, q, sizeelem);
+                q += stacksize;
+            }
+        }
+
+        va_end(q);
+    }
+    return result;
+}
+
+
+/**
+ * Support for array.dup property.
+ */
+struct Array2
+{
+    size_t length;
+    void*  ptr;
+}
+
+
+/**
+ *
+ */
+extern (C) long _adDupT(TypeInfo ti, Array2 a)
+out (result)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    assert(memcmp((*cast(Array2*)&result).ptr, a.ptr, a.length * sizeelem) == 0);
+}
+body
+{
+    Array2 r;
+
+    if (a.length)
+    {
+        auto sizeelem = ti.next.tsize();                // array element size
+        auto size = a.length * sizeelem;
+        r.ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        r.length = a.length;
+        memcpy(r.ptr, a.ptr, size);
+    }
+    return *cast(long*)(&r);
+}
+
+
+unittest
+{
+    int[] a;
+    int[] b;
+    int i;
+
+    a = new int[3];
+    a[0] = 1; a[1] = 2; a[2] = 3;
+    b = a.dup;
+    assert(b.length == 3);
+    for (i = 0; i < 3; i++)
+        assert(b[i] == i + 1);
+}
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);
                         }
                     }
                 }
