Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changeset 252

Show
Ignore:
Timestamp:
02/22/10 16:34:04 (15 years ago)
Author:
schveiguy
Message:

Applying patch for eliminating array stomping from the runtime. See bugzilla issue 3637.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/gc/gc.d

    r214 r252  
    3434        extern (C) void function() gc_enable; 
    3535        extern (C) void function() gc_disable; 
    3636        extern (C) void function() gc_collect; 
    3737        extern (C) void function() gc_minimize; 
    3838 
    3939        extern (C) uint function(void*) gc_getAttr; 
    4040        extern (C) uint function(void*, uint) gc_setAttr; 
    4141        extern (C) uint function(void*, uint) gc_clrAttr; 
    4242 
    4343        extern (C) void*  function(size_t, uint) gc_malloc; 
     44        extern (C) BlkInfo  function(size_t, uint) gc_malloc_bi; 
    4445        extern (C) void*  function(size_t, uint) gc_calloc; 
    4546        extern (C) void*  function(void*, size_t, uint ba) gc_realloc; 
    4647        extern (C) size_t function(void*, size_t, size_t) gc_extend; 
    4748        extern (C) size_t function(size_t) gc_reserve; 
    4849        extern (C) void   function(void*) gc_free; 
    4950 
    5051        extern (C) void*   function(void*) gc_addrOf; 
    5152        extern (C) size_t  function(void*) gc_sizeOf; 
    5253 
    5354        extern (C) BlkInfo function(void*) gc_query; 
     
    6768        pthis.gc_enable = &gc_enable; 
    6869        pthis.gc_disable = &gc_disable; 
    6970        pthis.gc_collect = &gc_collect; 
    7071        pthis.gc_minimize = &gc_minimize; 
    7172 
    7273        pthis.gc_getAttr = &gc_getAttr; 
    7374        pthis.gc_setAttr = &gc_setAttr; 
    7475        pthis.gc_clrAttr = &gc_clrAttr; 
    7576 
    7677        pthis.gc_malloc = &gc_malloc; 
     78        pthis.gc_malloc_bi = &gc_malloc_bi; 
    7779        pthis.gc_calloc = &gc_calloc; 
    7880        pthis.gc_realloc = &gc_realloc; 
    7981        pthis.gc_extend = &gc_extend; 
    8082        pthis.gc_reserve = &gc_reserve; 
    8183        pthis.gc_free = &gc_free; 
    8284 
    8385        pthis.gc_addrOf = &gc_addrOf; 
    8486        pthis.gc_sizeOf = &gc_sizeOf; 
    8587 
    8688        pthis.gc_query = &gc_query; 
     
    180182    return proxy.gc_clrAttr( p, a ); 
    181183} 
    182184 
    183185extern (C) void* gc_malloc( size_t sz, uint ba = 0 ) 
    184186{ 
    185187    if( proxy is null ) 
    186188        return _gc.malloc( sz, ba ); 
    187189    return proxy.gc_malloc( sz, ba ); 
    188190} 
    189191 
     192extern (C) BlkInfo gc_malloc_bi( size_t sz, uint ba = 0 ) 
     193{ 
     194    if( proxy is null ) 
     195    { 
     196        BlkInfo retval; 
     197        retval.base = _gc.malloc( sz, ba, &retval.size ); 
     198        retval.attr = ba; 
     199        return retval; 
     200    } 
     201    return proxy.gc_malloc_bi( sz, ba ); 
     202} 
     203 
    190204extern (C) void* gc_calloc( size_t sz, uint ba = 0 ) 
    191205{ 
    192206    if( proxy is null ) 
    193207        return _gc.calloc( sz, ba ); 
    194208    return proxy.gc_calloc( sz, ba ); 
    195209} 
    196210 
    197211extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 ) 
    198212{ 
    199213    if( proxy is null ) 
  • trunk/src/gc/gcx.d

    r220 r252  
    386386        else synchronized (gcLock) 
    387387        { 
    388388            return go(); 
    389389        } 
    390390    } 
    391391 
    392392 
    393393    /** 
    394394     * 
    395395     */ 
    396     void *malloc(size_t size, uint bits = 0
     396    void *malloc(size_t size, uint bits = 0, size_t *alloc_size = null
    397397    { 
    398398        if (!size) 
    399399        { 
     400            if(alloc_size) 
     401                *alloc_size = 0; 
    400402            return null; 
    401403        } 
    402404 
    403405        // Since a finalizer could launch a new thread, we always need to lock 
    404406        // when collecting.  The safest way to do this is to simply always lock 
    405407        // when allocating. 
    406408        synchronized (gcLock) 
    407409        { 
    408             return mallocNoSync(size, bits); 
    409         } 
    410     } 
    411  
    412  
    413     // 
    414     // 
    415     // 
    416     private void *mallocNoSync(size_t size, uint bits = 0
     410            return mallocNoSync(size, bits, alloc_size); 
     411        } 
     412    } 
     413 
     414 
     415    // 
     416    // 
     417    // 
     418    private void *mallocNoSync(size_t size, uint bits = 0, size_t *alloc_size = null
    417419    { 
    418420        assert(size != 0); 
    419421 
    420422        void *p = null; 
    421423        Bins bin; 
    422424 
    423425        //debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p)\n", size, gcx); 
    424426        assert(gcx); 
    425427        //debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self()); 
    426428 
     
    434436            bin = lastbin; 
    435437        else 
    436438        { 
    437439            bin = gcx.findBin(size); 
    438440            lastsize = size; 
    439441            lastbin = bin; 
    440442        } 
    441443 
    442444        if (bin < B_PAGE) 
    443445        { 
     446            if(alloc_size) 
     447                *alloc_size = binsize[bin]; 
    444448            int  state     = gcx.disabled ? 1 : 0; 
    445449            bool collected = false; 
    446450 
    447451            while (!gcx.bucket[bin] && !gcx.allocPage(bin)) 
    448452            { 
    449453                switch (state) 
    450454                { 
    451455                case 0: 
    452456                    gcx.fullcollectshell(); 
    453457                    collected = true; 
     
    470474 
    471475            // Return next item from free list 
    472476            gcx.bucket[bin] = (cast(List*)p).next; 
    473477            if( !(bits & BlkAttr.NO_SCAN) ) 
    474478                memset(p + size, 0, binsize[bin] - size); 
    475479            //debug(PRINTF) printf("\tmalloc => %x\n", p); 
    476480            debug (MEMSTOMP) memset(p, 0xF0, size); 
    477481        } 
    478482        else 
    479483        { 
    480             p = gcx.bigAlloc(size); 
     484            p = gcx.bigAlloc(size, alloc_size); 
    481485            if (!p) 
    482486                onOutOfMemoryError(); 
    483487        } 
    484488        size -= SENTINEL_EXTRA; 
    485489        p = sentinel_add(p); 
    486490        sentinel_init(p, size); 
    487491        gcx.log_malloc(p, size); 
    488492 
    489493        if (bits) 
    490494        { 
     
    493497 
    494498            gcx.setBits(pool, cast(size_t)(p - pool.baseAddr) / 16, bits); 
    495499        } 
    496500        return p; 
    497501    } 
    498502 
    499503 
    500504    /** 
    501505     * 
    502506     */ 
    503     void *calloc(size_t size, uint bits = 0
     507    void *calloc(size_t size, uint bits = 0, size_t *alloc_size = null
    504508    { 
    505509        if (!size) 
    506510        { 
     511            if(alloc_size) 
     512                *alloc_size = 0; 
    507513            return null; 
    508514        } 
    509515 
    510516        // Since a finalizer could launch a new thread, we always need to lock 
    511517        // when collecting.  The safest way to do this is to simply always lock 
    512518        // when allocating. 
    513519        synchronized (gcLock) 
    514520        { 
    515             return callocNoSync(size, bits); 
    516         } 
    517     } 
    518  
    519  
    520     // 
    521     // 
    522     // 
    523     private void *callocNoSync(size_t size, uint bits = 0
     521            return callocNoSync(size, bits, alloc_size); 
     522        } 
     523    } 
     524 
     525 
     526    // 
     527    // 
     528    // 
     529    private void *callocNoSync(size_t size, uint bits = 0, size_t *alloc_size = null
    524530    { 
    525531        assert(size != 0); 
    526532 
    527533        //debug(PRINTF) printf("calloc: %x len %d\n", p, len); 
    528         void *p = mallocNoSync(size, bits); 
     534        void *p = mallocNoSync(size, bits, alloc_size); 
    529535        memset(p, 0, size); 
    530536        return p; 
    531537    } 
    532538 
    533539 
    534540    /** 
    535541     * 
    536542     */ 
    537     void *realloc(void *p, size_t size, uint bits = 0
     543    void *realloc(void *p, size_t size, uint bits = 0, size_t *alloc_size = null
    538544    { 
    539545        // Since a finalizer could launch a new thread, we always need to lock 
    540546        // when collecting.  The safest way to do this is to simply always lock 
    541547        // when allocating. 
    542548        synchronized (gcLock) 
    543549        { 
    544             return reallocNoSync(p, size, bits); 
    545         } 
    546     } 
    547  
    548  
    549     // 
    550     // 
    551     // 
    552     private void *reallocNoSync(void *p, size_t size, uint bits = 0
     550            return reallocNoSync(p, size, bits, alloc_size); 
     551        } 
     552    } 
     553 
     554 
     555    // 
     556    // 
     557    // 
     558    private void *reallocNoSync(void *p, size_t size, uint bits = 0, size_t *alloc_size = null
    553559    { 
    554560        if (!size) 
    555561        {   if (p) 
    556562            {   freeNoSync(p); 
    557563                p = null; 
    558564            } 
     565            if(alloc_size) 
     566                *alloc_size = 0; 
    559567        } 
    560568        else if (!p) 
    561569        { 
    562             p = mallocNoSync(size, bits); 
     570            p = mallocNoSync(size, bits, alloc_size); 
    563571        } 
    564572        else 
    565573        {   void *p2; 
    566574            size_t psize; 
    567575 
    568576            //debug(PRINTF) printf("GC::realloc(p = %x, size = %u)\n", p, size); 
    569577            version (SENTINEL) 
    570578            { 
    571579                sentinel_Invariant(p); 
    572580                psize = *sentinel_size(p); 
     
    584592                            { 
    585593                                gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); 
    586594                                gcx.setBits(pool, biti, bits); 
    587595                            } 
    588596                            else 
    589597                            { 
    590598                                bits = gcx.getBits(pool, biti); 
    591599                            } 
    592600                        } 
    593601                    } 
    594                     p2 = mallocNoSync(size, bits); 
     602                    p2 = mallocNoSync(size, bits, alloc_size); 
    595603                    if (psize < size) 
    596604                        size = psize; 
    597605                    //debug(PRINTF) printf("\tcopying %d bytes\n",size); 
    598606                    memcpy(p2, p, size); 
    599607                    p = p2; 
    600608                } 
    601609            } 
    602610            else 
    603611            { 
    604612                psize = gcx.findSize(p);        // find allocated size 
     
    612620                    auto pool = gcx.findPool(p); 
    613621                    auto pagenum = (p - pool.baseAddr) / PAGESIZE; 
    614622 
    615623                    if (newsz < psz) 
    616624                    {   // Shrink in place 
    617625                        synchronized (gcLock) 
    618626                        { 
    619627                            debug (MEMSTOMP) memset(p + size, 0xF2, psize - size); 
    620628                            pool.freePages(pagenum + newsz, psz - newsz); 
    621629                        } 
     630                        if(alloc_size) 
     631                            *alloc_size = newsz * PAGESIZE; 
    622632                        return p; 
    623633                    } 
    624634                    else if (pagenum + newsz <= pool.npages) 
    625635                    { 
    626636                        // Attempt to expand in place 
    627637                        synchronized (gcLock) 
    628638                        { 
    629639                            for (size_t i = pagenum + psz; 1;) 
    630640                            { 
    631641                                if (i == pagenum + newsz) 
    632642                                { 
    633643                                    debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize); 
    634644                                    memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz); 
     645                                    if(alloc_size) 
     646                                        *alloc_size = newsz * PAGESIZE; 
    635647                                    return p; 
    636648                                } 
    637649                                if (i == pool.ncommitted) 
    638650                                { 
    639651                                    auto u = pool.extendPages(pagenum + newsz - pool.ncommitted); 
    640652                                    if (u == OPFAIL) 
    641653                                        break; 
    642654                                    i = pagenum + newsz; 
    643655                                    continue; 
    644656                                } 
     
    664676                            { 
    665677                                gcx.clrBits(pool, biti, BlkAttr.ALL_BITS); 
    666678                                gcx.setBits(pool, biti, bits); 
    667679                            } 
    668680                            else 
    669681                            { 
    670682                                bits = gcx.getBits(pool, biti); 
    671683                            } 
    672684                        } 
    673685                    } 
    674                     p2 = mallocNoSync(size, bits); 
     686                    p2 = mallocNoSync(size, bits, alloc_size); 
    675687                    if (psize < size) 
    676688                        size = psize; 
    677689                    //debug(PRINTF) printf("\tcopying %d bytes\n",size); 
    678690                    memcpy(p2, p, size); 
    679691                    p = p2; 
    680692                } 
     693                else if(alloc_size) 
     694                    *alloc_size = psize; 
    681695            } 
    682696        } 
    683697        return p; 
    684698    } 
    685699 
    686700 
    687701    /** 
    688702     * Attempt to in-place enlarge the memory block pointed to by p by at least 
    689703     * minbytes beyond its current capacity, up to a maximum of maxsize.  This 
    690704     * does not attempt to move the memory block (like realloc() does). 
     
    17741788            size_t offset = cast(size_t)(p - pool.baseAddr); 
    17751789            size_t pn = offset / PAGESIZE; 
    17761790            Bins   bin = cast(Bins)pool.pagetable[pn]; 
    17771791 
    17781792            //////////////////////////////////////////////////////////////////// 
    17791793            // findAddr 
    17801794            //////////////////////////////////////////////////////////////////// 
    17811795 
    17821796            if (bin <= B_PAGE) 
    17831797            { 
    1784                 info.base = pool.baseAddr + (offset & notbinsize[bin]); 
     1798                info.base = cast(void*)((cast(size_t)p) & notbinsize[bin]); 
    17851799            } 
    17861800            else if (bin == B_PAGEPLUS) 
    17871801            { 
    17881802                do 
    17891803                {   --pn, offset -= PAGESIZE; 
    17901804                } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); 
    17911805 
    17921806                info.base = pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1))); 
    17931807 
    17941808                // fix bin for use by size calc below 
     
    19221936            minAddr = pooltable[0].baseAddr; 
    19231937            maxAddr = pooltable[npools - 1].topAddr; 
    19241938        } 
    19251939    } 
    19261940 
    19271941 
    19281942    /** 
    19291943     * Allocate a chunk of memory that is larger than a page. 
    19301944     * Return null if out of memory. 
    19311945     */ 
    1932     void *bigAlloc(size_t size
     1946    void *bigAlloc(size_t size, size_t *alloc_size = null
    19331947    { 
    19341948        Pool*  pool; 
    19351949        size_t npages; 
    19361950        size_t n; 
    19371951        size_t pn; 
    19381952        size_t freedpages; 
    19391953        void*  p; 
    19401954        int    state; 
    19411955        bool   collected = false; 
    19421956 
     
    19992013            } 
    20002014        } 
    20012015 
    20022016      L1: 
    20032017        pool.pagetable[pn] = B_PAGE; 
    20042018        if (npages > 1) 
    20052019            memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1); 
    20062020        p = pool.baseAddr + pn * PAGESIZE; 
    20072021        memset(cast(char *)p + size, 0, npages * PAGESIZE - size); 
    20082022        debug (MEMSTOMP) memset(p, 0xF1, size); 
     2023        if(alloc_size) 
     2024            *alloc_size = npages * PAGESIZE; 
    20092025        //debug(PRINTF) printf("\tp = %x\n", p); 
    20102026        return p; 
    20112027 
    20122028      Lnomemory: 
    20132029        return null; // let caller handle the error 
    20142030    } 
    20152031 
    20162032 
    20172033    /** 
    20182034     * Allocate a new pool with at least npages in it. 
  • trunk/src/rt/lifetime.d

    r220 r252  
    4040        void*  base; 
    4141        size_t size; 
    4242        uint   attr; 
    4343    } 
    4444 
    4545    extern (C) uint gc_getAttr( in void* p ); 
    4646    extern (C) uint gc_setAttr( in void* p, uint a ); 
    4747    extern (C) uint gc_clrAttr( in void* p, uint a ); 
    4848 
    4949    extern (C) void*  gc_malloc( size_t sz, uint ba = 0 ); 
     50    extern (C) BlkInfo  gc_malloc_bi( size_t sz, uint ba = 0 ); 
    5051    extern (C) void*  gc_calloc( size_t sz, uint ba = 0 ); 
    5152    extern (C) size_t gc_extend( void* p, size_t mx, size_t sz ); 
    5253    extern (C) void   gc_free( void* p ); 
    5354 
    5455    extern (C) void*   gc_addrOf( in void* p ); 
    5556    extern (C) size_t  gc_sizeOf( in void* p ); 
    5657    extern (C) BlkInfo gc_query( in void* p ); 
    5758 
    5859    extern (C) void onFinalizeError( ClassInfo c, Throwable e ); 
    5960    extern (C) void onOutOfMemoryError(); 
    6061 
    6162    extern (C) void _d_monitordelete(Object h, bool det = true); 
    6263 
    6364    enum 
    6465    { 
    6566        PAGESIZE = 4096 
    6667    } 
    6768 
    6869    alias bool function(Object) CollectHandler; 
    6970    __gshared CollectHandler collectHandler = null; 
     71 
     72enum : size_t 
     73       { 
     74           LENGTHMASK = ~(cast(size_t)0x0ff), 
     75           BIGLENGTHMASK = ~(cast(size_t)PAGESIZE - 1), 
     76           SMALLPAD = 1, 
     77           MEDPAD = ushort.sizeof, 
     78           LARGEPAD = size_t.sizeof * 2 + 1, 
     79       } 
    7080} 
    7181 
    7282 
    7383/** 
    7484 * 
    7585 */ 
    7686extern (C) void* _d_allocmemory(size_t sz) 
    7787{ 
    7888    return gc_malloc(sz); 
    7989} 
     
    92102         * using AddRef() and Release().  They get free'd by C's free() 
    93103         * function called by Release() when Release()'s reference count goes 
    94104         * to zero. 
    95105     */ 
    96106        p = malloc(ci.init.length); 
    97107        if (!p) 
    98108            onOutOfMemoryError(); 
    99109    } 
    100110    else 
    101111    { 
    102         p = gc_malloc(ci.init.length
     112        auto info = gc_malloc_bi(ci.init.length + __arrayPad(ci.init.length)
    103113                      BlkAttr.FINALIZE | (ci.m_flags & 2 ? BlkAttr.NO_SCAN : 0)); 
     114        p = info.base; 
     115        // only init ghost array length if noscan is set.  Scanned blocks are 
     116        // initialized to 0 by the gc. 
     117        if(ci.flags & 2) 
     118        { 
     119            // initialize the ghost array length at the end of the block.  This 
     120            // prevents accidental stomping in the case where a class contains 
     121            // a static array and someone tries to append to a slice of that 
     122            // array. 
     123            *((cast(size_t *)(p + info.size)) - 1) = 0; 
     124        } 
    104125        debug(PRINTF) printf(" p = %p\n", p); 
    105126    } 
    106127 
    107128    debug(PRINTF) 
    108129    { 
    109130        printf("p = %p\n", p); 
    110131        printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length); 
    111132        printf("vptr = %p\n", *cast(void**) ci.init); 
    112133        printf("vtbl[0] = %p\n", (*cast(void***) ci.init)[0]); 
    113134        printf("vtbl[1] = %p\n", (*cast(void***) ci.init)[1]); 
     
    172193        } 
    173194        else 
    174195        { 
    175196            rt_finalize(cast(void*) *p); 
    176197        } 
    177198        gc_free(cast(void*) *p); 
    178199        *p = null; 
    179200    } 
    180201} 
    181202 
     203/** dummy class used to lock for shared array appending */ 
     204private class ArrayAllocLengthLock 
     205{} 
     206 
     207 
     208/** 
     209  Set the allocated length of the array block.  This is called 
     210  any time an array is appended to or its length is set. 
     211 
     212  The allocated block looks like this for blocks < PAGESIZE: 
     213 
     214  |elem0|elem1|elem2|...|elemN-1|emptyspace|N*elemsize| 
     215 
     216 
     217  The size of the allocated length at the end depends on the block size: 
     218 
     219  a block of 16 to 256 bytes has an 8-bit length. 
     220 
     221  a block with 512 to pagesize/2 bytes has a 16-bit length. 
     222 
     223  For blocks >= pagesize, the length is a size_t and is at the beginning of the 
     224  block.  The reason we have to do this is because the block can extend into 
     225  more pages, so we cannot trust the block length if it sits at the end of the 
     226  block, because it might have just been extended.  If we can prove in the 
     227  future that the block is unshared, we may be able to change this, but I'm not 
     228  sure it's important. 
     229 
     230  In order to do put the length at the front, we have to provide 2*size_t bytes 
     231  buffer space in case the block has to be aligned properly.  For example, on a 
     232  32-bit OS, doubles should be 8-byte aligned.  In addition, we need the 
     233  sentinel byte to prevent accidental pointers to the next block.  Because of 
     234  the extra overhead, we only do this for page size and above, where the 
     235  overhead is minimal compared to the block size. 
     236 
     237  So for those blocks, it looks like: 
     238 
     239  |N*elemsize|padding|elem0|elem1|...|elemN-1|emptyspace|sentinelbyte| 
     240 
     241  where elem0 starts 8 bytes after the first byte. 
     242  */ 
     243bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, size_t oldlength = ~0) 
     244{ 
     245    if(info.size <= 256) 
     246    { 
     247        if(newlength + SMALLPAD > info.size) 
     248            // new size does not fit inside block 
     249            return false; 
     250        auto length = cast(ubyte *)(info.base + info.size - SMALLPAD); 
     251        if(oldlength != ~0) 
     252        { 
     253            if(isshared) 
     254            { 
     255                synchronized(typeid(ArrayAllocLengthLock)) 
     256                { 
     257                    if(*length == cast(ubyte)oldlength) 
     258                        *length = cast(ubyte)newlength; 
     259                    else 
     260                        return false; 
     261                } 
     262            } 
     263            else 
     264            { 
     265                if(*length == cast(ubyte)oldlength) 
     266                    *length = cast(ubyte)newlength; 
     267                else 
     268                    return false; 
     269            } 
     270        } 
     271        else 
     272        { 
     273            // setting the initial length, no lock needed 
     274            *length = cast(ubyte)newlength; 
     275        } 
     276    } 
     277    else if(info.size < PAGESIZE) 
     278    { 
     279        if(newlength + MEDPAD > info.size) 
     280            // new size does not fit inside block 
     281            return false; 
     282        auto length = cast(ushort *)(info.base + info.size - MEDPAD); 
     283        if(oldlength != ~0) 
     284        { 
     285            if(isshared) 
     286            { 
     287                synchronized(typeid(ArrayAllocLengthLock)) 
     288                { 
     289                    if(*length == oldlength) 
     290                        *length = cast(ushort)newlength; 
     291                    else 
     292                        return false; 
     293                } 
     294            } 
     295            else 
     296            { 
     297                if(*length == oldlength) 
     298                    *length = cast(ushort)newlength; 
     299                else 
     300                    return false; 
     301            } 
     302        } 
     303        else 
     304        { 
     305            // setting the initial length, no lock needed 
     306            *length = cast(ushort)newlength; 
     307        } 
     308    } 
     309    else 
     310    { 
     311        if(newlength + LARGEPAD > info.size) 
     312            // new size does not fit inside block 
     313            return false; 
     314        auto length = cast(size_t *)(info.base); 
     315        if(oldlength != ~0) 
     316        { 
     317            if(isshared) 
     318            { 
     319                synchronized(typeid(ArrayAllocLengthLock)) 
     320                { 
     321                    if(*length == oldlength) 
     322                        *length = newlength; 
     323                    else 
     324                        return false; 
     325                } 
     326            } 
     327            else 
     328            { 
     329                if(*length == oldlength) 
     330                    *length = newlength; 
     331                else 
     332                    return false; 
     333            } 
     334        } 
     335        else 
     336        { 
     337            // setting the initial length, no lock needed 
     338            *length = newlength; 
     339        } 
     340    } 
     341    return true; // resize succeeded 
     342} 
     343 
     344/** 
     345  get the start of the array for the given block 
     346  */ 
     347void *__arrayStart(BlkInfo info) 
     348{ 
     349    return info.base + ((info.size & BIGLENGTHMASK) ? 2*size_t.sizeof : 0); 
     350} 
     351 
     352size_t __arrayPad(size_t size) 
     353{ 
     354    return (size & BIGLENGTHMASK) ? LARGEPAD : (size & LENGTHMASK) ? MEDPAD : SMALLPAD; 
     355} 
     356 
     357/** 
     358  cache for the lookup of the block info 
     359  */ 
     360enum N_CACHE_BLOCKS=8; 
     361static if(N_CACHE_BLOCKS==1) 
     362{ 
     363    version=single_cache; 
     364    // note this is TLS, so no need to sync. 
     365    BlkInfo __blkcache; 
     366} 
     367else 
     368{ 
     369    //version=simple_cache; // uncomment to test simple cache strategy 
     370 
     371    // ensure N_CACHE_BLOCKS is power of 2. 
     372    static assert(!((N_CACHE_BLOCKS - 1) & N_CACHE_BLOCKS)); 
     373 
     374    // note this is TLS, so no need to sync. 
     375    BlkInfo __blkcache[N_CACHE_BLOCKS]; 
     376    int __nextBlkIdx; 
     377} 
     378 
     379 
     380/** 
     381  Get the cached block info of an interior pointer.  Returns null if the 
     382  interior pointer's block is not cached. 
     383  */ 
     384BlkInfo *__getBlkInfo(void *interior) 
     385{ 
     386    version(single_cache) 
     387    { 
     388        BlkInfo *ptr = &__blkcache; 
     389        if(ptr.base <= interior && (interior - ptr.base) < ptr.size) 
     390            return ptr; 
     391        return null; // not in cache. 
     392    } 
     393    else 
     394    { 
     395        version(simple_cache) 
     396        { 
     397            BlkInfo *ptr = __blkcache.ptr; 
     398            foreach(i; 0..N_CACHE_BLOCKS) 
     399            { 
     400                if(ptr.base <= interior && (interior - ptr.base) < ptr.size) 
     401                    return ptr; 
     402                ptr++; 
     403            } 
     404        } 
     405        else 
     406        { 
     407            // try to do a smart lookup, using __nextBlkIdx as the "head" 
     408            BlkInfo *ptr = __blkcache.ptr; 
     409            for(int i = __nextBlkIdx; i >= 0; --i) 
     410            { 
     411                if(ptr[i].base <= interior && (interior - ptr[i].base) < ptr.size) 
     412                    return ptr + i; 
     413            } 
     414 
     415            for(int i = N_CACHE_BLOCKS - 1; i > __nextBlkIdx; --i) 
     416            { 
     417                if(ptr[i].base <= interior && (interior - ptr[i].base) < ptr.size) 
     418                    return ptr + i; 
     419            } 
     420        } 
     421        return null; // not in cache. 
     422    } 
     423} 
     424 
     425void __insertBlkInfoCache(BlkInfo bi, BlkInfo *curpos) 
     426{ 
     427    version(single_cache) 
     428    { 
     429        __blkcache = bi; 
     430    } 
     431    else 
     432    { 
     433        version(simple_cache) 
     434        { 
     435            if(curpos) 
     436                *curpos = bi; 
     437            else 
     438            { 
     439                // note, this is a super-simple algorithm that does not care about 
     440                // most recently used.  It simply uses a round-robin technique to 
     441                // cache block info.  This means that the ordering of the cache 
     442                // doesn't mean anything.  Certain patterns of allocation may 
     443                // render the cache near-useless. 
     444                __blkcache.ptr[__nextBlkIdx] = bi; 
     445                __nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1); 
     446            } 
     447        } 
     448        else 
     449        { 
     450            // 
     451            // strategy: If the block currently is in the cache, swap it with 
     452            // the head element.  Otherwise, move the head element up by one, 
     453            // and insert it there. 
     454            // 
     455            auto cache = __blkcache.ptr; 
     456            if(!curpos) 
     457            { 
     458                __nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1); 
     459                curpos = cache + __nextBlkIdx; 
     460            } 
     461            else if(curpos !is cache + __nextBlkIdx) 
     462            { 
     463                *curpos = cache[__nextBlkIdx]; 
     464                curpos = cache + __nextBlkIdx; 
     465            } 
     466            *curpos = bi; 
     467        } 
     468    } 
     469} 
    182470 
    183471/** 
    184472 * Allocate a new array of length elements. 
    185473 * ti is the type of the resulting array, or pointer to element. 
    186474 * (For when the array is initialized to 0) 
    187475 */ 
    188476extern (C) ulong _d_newarrayT(TypeInfo ti, size_t length) 
    189477{ 
    190     void* p; 
    191478    ulong result; 
    192479    auto size = ti.next.tsize();                // array element size 
    193480 
    194481    debug(PRINTF) printf("_d_newarrayT(length = x%x, size = %d)\n", length, size); 
    195482    if (length == 0 || size == 0) 
    196483        result = 0; 
    197484    else 
    198485    { 
    199486        version (D_InlineAsm_X86) 
    200487        { 
    201488            asm 
    202489            { 
    203490                mov     EAX,size        ; 
    204491                mul     EAX,length      ; 
    205492                mov     size,EAX        ; 
    206493                jc      Loverflow       ; 
    207494            } 
    208495        } 
    209496        else 
    210497            size *= length; 
    211         p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
    212         debug(PRINTF) printf(" p = %p\n", p); 
    213         memset(p, 0, size); 
    214         result = cast(ulong)length + (cast(ulong)cast(uint)p << 32); 
     498        // increase the size by 1 if the actual requested size is < 256, 
     499        // by size_t.sizeof if it's >= 256 
     500         
     501        auto info = gc_malloc_bi(size + __arrayPad(size), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     502        debug(PRINTF) printf(" p = %p\n", info.base); 
     503        // update the length of the array 
     504        memset(info.base, 0, size); 
     505        auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     506        __setArrayAllocLength(info, size, isshared); 
     507        result = cast(ulong)length + (cast(ulong)cast(size_t)__arrayStart(info) << 32); 
    215508    } 
    216509    return result; 
    217510 
    218511Loverflow: 
    219512    onOutOfMemoryError(); 
    220513} 
    221514 
    222515/** 
    223516 * For when the array has a non-zero initializer. 
    224517 */ 
     
    241534            asm 
    242535            { 
    243536                mov     EAX,size        ; 
    244537                mul     EAX,length      ; 
    245538                mov     size,EAX        ; 
    246539                jc      Loverflow       ; 
    247540            } 
    248541        } 
    249542        else 
    250543            size *= length; 
    251         auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
    252         debug(PRINTF) printf(" p = %p\n", p); 
     544 
     545        auto info = gc_malloc_bi(size + __arrayPad(size), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     546        debug(PRINTF) printf(" p = %p\n", info.base); 
    253547        if (isize == 1) 
    254             memset(p, *cast(ubyte*)q, size); 
     548            memset(info.base, *cast(ubyte*)q, size); 
    255549        else if (isize == int.sizeof) 
    256550        { 
    257551            int init = *cast(int*)q; 
    258552            size /= int.sizeof; 
    259553            for (size_t u = 0; u < size; u++) 
    260554            { 
    261                 (cast(int*)p)[u] = init; 
     555                (cast(int*)info.base)[u] = init; 
    262556            } 
    263557        } 
    264558        else 
    265559        { 
    266560            for (size_t u = 0; u < size; u += isize) 
    267561            { 
    268                 memcpy(p + u, q, isize); 
     562                memcpy(info.base + u, q, isize); 
    269563            } 
    270564        } 
    271565        va_end(q); 
    272         result = cast(ulong)length + (cast(ulong)cast(uint)p << 32); 
     566        auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     567        __setArrayAllocLength(info, size, isshared); 
     568        result = cast(ulong)length + (cast(ulong)cast(uint)__arrayStart(info) << 32); 
    273569    } 
    274570    return result; 
    275571 
    276572Loverflow: 
    277573    onOutOfMemoryError(); 
    278574} 
    279575 
    280576/** 
    281577 * 
    282578 */ 
     
    297593            void[] p; 
    298594 
    299595            debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims); 
    300596            if (ndims == 1) 
    301597            { 
    302598                auto r = _d_newarrayT(ti, dim); 
    303599                p = *cast(void[]*)(&r); 
    304600            } 
    305601            else 
    306602            { 
    307                 p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim]; 
     603                auto allocsize = (void[]).sizeof * dim; 
     604                auto info = gc_malloc_bi(allocsize + __arrayPad(allocsize)); 
     605                auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     606                __setArrayAllocLength(info, allocsize, isshared); 
     607                p = __arrayStart(info)[0 .. dim]; 
    308608                for (int i = 0; i < dim; i++) 
    309609                { 
    310610                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1); 
    311611                } 
    312612            } 
    313613            return p; 
    314614        } 
    315615 
    316616        size_t* pdim = cast(size_t *)q; 
    317617        result = cast(ulong)foo(ti, pdim, ndims); 
     
    350650            size_t dim = *pdim; 
    351651            void[] p; 
    352652 
    353653            if (ndims == 1) 
    354654            { 
    355655                auto r = _d_newarrayiT(ti, dim); 
    356656                p = *cast(void[]*)(&r); 
    357657            } 
    358658            else 
    359659            { 
    360                 p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim]; 
     660                auto allocsize = (void[]).sizeof * dim; 
     661                auto info = gc_malloc_bi(allocsize + __arrayPad(allocsize)); 
     662                auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     663                __setArrayAllocLength(info, allocsize, isshared); 
     664                p = __arrayStart(info)[0 .. dim]; 
    361665                for (int i = 0; i < dim; i++) 
    362666                { 
    363667                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1); 
    364668                } 
    365669            } 
    366670            return p; 
    367671        } 
    368672 
    369673        size_t* pdim = cast(size_t *)q; 
    370674        result = cast(ulong)foo(ti, pdim, ndims); 
     
    574878        else 
    575879        { 
    576880            size_t newsize = sizeelem * newlength; 
    577881 
    578882            if (newsize / newlength != sizeelem) 
    579883                goto Loverflow; 
    580884        } 
    581885 
    582886        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength); 
    583887 
     888        auto   isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     889 
    584890        if (p.data) 
    585891        { 
    586892            newdata = p.data; 
    587893            if (newlength > p.length) 
    588894            { 
    589895                size_t size = p.length * sizeelem; 
    590                 auto   info = gc_query(p.data); 
    591  
    592                 if (info.size <= newsize || info.base != p.data) 
     896                auto   bic = !isshared ? __getBlkInfo(p.data) : null; 
     897                auto   info = bic ? *bic : gc_query(p.data); 
     898                // calculate the extent of the array given the base. 
     899                size_t offset = p.data - __arrayStart(info); 
     900                if(info.size >= PAGESIZE) 
    593901                { 
    594                     if (info.size >= PAGESIZE && info.base == p.data) 
    595                     {   // Try to extend in-place 
    596                         auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size); 
    597                         if (u) 
     902                    // size of array is at the front of the block 
     903                    if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
     904                    { 
     905                        // check to see if it failed because there is not 
     906                        // enough space 
     907                        if(*(cast(size_t*)info.base) == size + offset) 
    598908                        { 
    599                             goto L1; 
     909                            // not enough space, try extending 
     910                            auto extendsize = newsize + offset + LARGEPAD - info.size; 
     911                            auto u = gc_extend(p.data, extendsize, extendsize); 
     912                            if(u) 
     913                            { 
     914                                // extend worked, now try setting the length 
     915                                // again. 
     916                                info.size = u; 
     917                                if(__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
     918                                { 
     919                                    if(!isshared) 
     920                                        __insertBlkInfoCache(info, bic); 
     921                                    goto L1; 
     922                                } 
     923                            } 
    600924                        } 
     925 
     926                        // couldn't do it, reallocate 
     927                        info = gc_malloc_bi(newsize + LARGEPAD, info.attr); 
     928                        __setArrayAllocLength(info, newsize, isshared); 
     929                        if(!isshared) 
     930                            __insertBlkInfoCache(info, bic); 
     931                        newdata = cast(byte *)(info.base + size_t.sizeof * 2); 
     932                        newdata[0 .. size] = p.data[0 .. size]; 
    601933                    } 
    602                     newdata = cast(byte *)gc_malloc(newsize + 1, info.attr); 
     934                } 
     935                else if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
     936                { 
     937                    // could not resize in place 
     938                    info = gc_malloc_bi(newsize + __arrayPad(newsize), info.attr); 
     939                    __setArrayAllocLength(info, newsize, isshared); 
     940                    if(!isshared) 
     941                        __insertBlkInfoCache(info, bic); 
     942                    newdata = cast(byte *)__arrayStart(info); 
    603943                    newdata[0 .. size] = p.data[0 .. size]; 
     944                } 
     945                else if(!isshared && !bic) 
     946                { 
     947                    // add this to the cache, it wasn't present previously. 
     948                    __insertBlkInfoCache(info, null); 
    604949                } 
    605950             L1: 
    606951                newdata[size .. newsize] = 0; 
    607952            } 
    608953        } 
    609954        else 
    610955        { 
    611             newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     956            // pointer was null, need to allocate 
     957            auto info = gc_malloc_bi(newsize + __arrayPad(newsize), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     958            __setArrayAllocLength(info, newsize, isshared); 
     959            if(!isshared) 
     960                __insertBlkInfoCache(info, null); 
     961            newdata = cast(byte *)__arrayStart(info); 
     962            newdata[0 .. newsize] = 0; 
    612963        } 
    613964    } 
    614965    else 
    615966    { 
    616967        newdata = p.data; 
    617968    } 
    618969 
    619970    p.data = newdata; 
    620971    p.length = newlength; 
    621972    return newdata[0 .. newlength]; 
     
    6741026        else 
    6751027        { 
    6761028            size_t newsize = sizeelem * newlength; 
    6771029 
    6781030            if (newsize / newlength != sizeelem) 
    6791031                goto Loverflow; 
    6801032        } 
    6811033        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength); 
    6821034 
    6831035        size_t size = p.length * sizeelem; 
    684  
     1036        auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
    6851037        if (p.data) 
    6861038        { 
    6871039            newdata = p.data; 
    6881040            if (newlength > p.length) 
    6891041            { 
    690                 auto info = gc_query(p.data); 
    691  
    692                 if (info.size <= newsize || info.base != p.data) 
     1042                auto   bic = !isshared ? __getBlkInfo(p.data) : null; 
     1043                auto   info = bic ? *bic : gc_query(p.data); 
     1044 
     1045                // calculate the extent of the array given the base. 
     1046                size_t offset = p.data - __arrayStart(info); 
     1047                if(info.size >= PAGESIZE) 
    6931048                { 
    694                     if (info.size >= PAGESIZE && info.base == p.data) 
    695                     {   // Try to extend in-place 
    696                         auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size); 
    697                         if (u) 
     1049                    // size of array is at the front of the block 
     1050                    if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
     1051                    { 
     1052                        // check to see if it failed because there is not 
     1053                        // enough space 
     1054                        if(*(cast(size_t*)info.base) == size + offset) 
    6981055                        { 
    699                             goto L1; 
     1056                            // not enough space, try extending 
     1057                            auto extendsize = newsize + offset + LARGEPAD - info.size; 
     1058                            auto u = gc_extend(p.data, extendsize, extendsize); 
     1059                            if(u) 
     1060                            { 
     1061                                // extend worked, now try setting the length 
     1062                                // again. 
     1063                                info.size = u; 
     1064                                if(__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
     1065                                { 
     1066                                    if(!isshared) 
     1067                                        __insertBlkInfoCache(info, bic); 
     1068                                    goto L1; 
     1069                                } 
     1070                            } 
    7001071                        } 
     1072 
     1073                        // couldn't do it, reallocate 
     1074                        info = gc_malloc_bi(newsize + LARGEPAD, info.attr); 
     1075                        __setArrayAllocLength(info, newsize, isshared); 
     1076                        if(!isshared) 
     1077                            __insertBlkInfoCache(info, bic); 
     1078                        newdata = cast(byte *)(info.base + size_t.sizeof * 2); 
     1079                        newdata[0 .. size] = p.data[0 .. size]; 
    7011080                    } 
    702                     newdata = cast(byte *)gc_malloc(newsize + 1, info.attr); 
     1081                } 
     1082                else if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
     1083                { 
     1084                    // could not resize in place 
     1085                    info = gc_malloc_bi(newsize + __arrayPad(newsize), info.attr); 
     1086                    __setArrayAllocLength(info, newsize, isshared); 
     1087                    if(!isshared) 
     1088                        __insertBlkInfoCache(info, bic); 
     1089                    newdata = cast(byte *)__arrayStart(info); 
    7031090                    newdata[0 .. size] = p.data[0 .. size]; 
     1091                } 
     1092                else if(!isshared && !bic) 
     1093                { 
     1094                    // add this to the cache, it wasn't present previously. 
     1095                    __insertBlkInfoCache(info, null); 
     1096                } 
    7041097                L1: ; 
    705                 } 
    7061098            } 
    7071099        } 
    7081100        else 
    7091101        { 
    710             newdata = cast(byte *)gc_malloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1102            // length was zero, need to allocate 
     1103            auto info = gc_malloc_bi(newsize + __arrayPad(newsize), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1104            __setArrayAllocLength(info, newsize, isshared); 
     1105            if(!isshared) 
     1106                __insertBlkInfoCache(info, null); 
     1107            newdata = cast(byte *)__arrayStart(info); 
    7111108        } 
    7121109 
    7131110        auto q = initializer.ptr; // pointer to initializer 
    7141111 
    7151112        if (newsize > size) 
    7161113        { 
    7171114            if (initsize == 1) 
    7181115            { 
    7191116                debug(PRINTF) printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q); 
    7201117                newdata[size .. newsize] = *(cast(byte*)q); 
     
    7411138    onOutOfMemoryError(); 
    7421139} 
    7431140 
    7441141 
    7451142/** 
    7461143 * Append y[] to array x[]. 
    7471144 * size is size of each array element. 
    7481145 */ 
    7491146extern (C) long _d_arrayappendT(TypeInfo ti, Array *px, byte[] y) 
    7501147{ 
     1148    // only optimize array append where ti is not a shared type 
    7511149    auto sizeelem = ti.next.tsize();            // array element size 
    752     auto info = gc_query(px.data); 
     1150    auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     1151    auto bic = !isshared ? __getBlkInfo(px.data) : null; 
     1152    auto info = bic ? *bic : gc_query(px.data); 
    7531153    auto length = px.length; 
    7541154    auto newlength = length + y.length; 
    7551155    auto newsize = newlength * sizeelem; 
    756  
    757     if (info.size < newsize || info.base != px.data) 
    758     {   byte* newdata; 
    759  
    760         if (info.size >= PAGESIZE && info.base == px.data) 
    761         {   // Try to extend in-place 
    762             auto u = gc_extend(px.data, (newsize + 1) - info.size, (newsize + 1) - info.size); 
    763             if (u) 
    764             { 
    765                 goto L1; 
    766             } 
    767         } 
    768         newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr); 
     1156    auto size = length * sizeelem; 
     1157 
     1158    // calculate the extent of the array given the base. 
     1159    size_t offset = px.data - __arrayStart(info); 
     1160    if(info.size >= PAGESIZE) 
     1161    { 
     1162        // size of array is at the front of the block 
     1163        if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
     1164        { 
     1165            // check to see if it failed because there is not 
     1166            // enough space 
     1167            if(*(cast(size_t*)info.base) == size + offset) 
     1168            { 
     1169                // not enough space, try extending 
     1170                auto extendsize = newsize + offset + LARGEPAD - info.size; 
     1171                auto u = gc_extend(px.data, extendsize, extendsize); 
     1172                if(u) 
     1173                { 
     1174                    // extend worked, now try setting the length 
     1175                    // again. 
     1176                    info.size = u; 
     1177                    if(__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
     1178                    { 
     1179                        if(!isshared) 
     1180                            __insertBlkInfoCache(info, bic); 
     1181                        goto L1; 
     1182                    } 
     1183                } 
     1184            } 
     1185 
     1186            // couldn't do it, reallocate 
     1187            info = gc_malloc_bi(newCapacity(newlength, sizeelem) + LARGEPAD, info.attr); 
     1188            __setArrayAllocLength(info, newsize, isshared); 
     1189            if(!isshared) 
     1190                __insertBlkInfoCache(info, bic); 
     1191            auto newdata = cast(byte *)info.base + size_t.sizeof * 2; 
     1192            memcpy(newdata, px.data, length * sizeelem); 
     1193            px.data = newdata; 
     1194        } 
     1195    } 
     1196    else if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
     1197    { 
     1198        // could not resize in place 
     1199        auto allocsize = newCapacity(newlength, sizeelem); 
     1200        info = gc_malloc_bi(allocsize + __arrayPad(allocsize), info.attr); 
     1201        __setArrayAllocLength(info, newsize, isshared); 
     1202        if(!isshared) 
     1203            __insertBlkInfoCache(info, bic); 
     1204        auto newdata = cast(byte *)__arrayStart(info); 
    7691205        memcpy(newdata, px.data, length * sizeelem); 
    7701206        px.data = newdata; 
    7711207    } 
     1208    else if(!isshared && !bic) 
     1209    { 
     1210        __insertBlkInfoCache(info, null); 
     1211    } 
     1212 
     1213 
    7721214  L1: 
    7731215    px.length = newlength; 
    7741216    memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem); 
    7751217    return *cast(long*)px; 
    7761218} 
    7771219 
    7781220 
    7791221/** 
    7801222 * 
    7811223 */ 
     
    8441286        newcap = newext > newcap ? newext : newcap; 
    8451287        debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size); 
    8461288    } 
    8471289    return newcap; 
    8481290} 
    8491291 
    8501292 
    8511293/** 
    8521294 * 
    8531295 */ 
    854 extern (C) byte[] _d_arrayappendcT(TypeInfo ti, ref byte[] x, ...) 
    855 
    856     auto sizeelem = ti.next.tsize();            // array element size 
    857     auto info = gc_query(x.ptr); 
    858     auto length = x.length; 
    859     auto newlength = length + 1; 
    860     auto newsize = newlength * sizeelem; 
    861  
    862     assert(info.size == 0 || length * sizeelem <= info.size); 
    863  
    864     debug(PRINTF) printf("_d_arrayappendcT(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size); 
    865  
    866     if (info.size <= newsize || info.base != x.ptr) 
    867     {   byte* newdata; 
    868  
    869         if (info.size >= PAGESIZE && info.base == x.ptr) 
    870         {   // Try to extend in-place 
    871             auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size); 
    872             if (u) 
    873             { 
    874                 goto L1; 
    875             } 
    876         } 
    877         debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size); 
    878         auto newcap = newCapacity(newlength, sizeelem); 
    879         assert(newcap >= newlength * sizeelem); 
    880         newdata = cast(byte *)gc_malloc(newcap + 1, info.attr); 
    881         memcpy(newdata, x.ptr, length * sizeelem); 
    882         (cast(void**)(&x))[1] = newdata; 
    883     } 
    884   L1: 
    885     byte *argp = cast(byte *)(&ti + 2); 
    886  
    887     *cast(size_t *)&x = newlength; 
    888     x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem]; 
    889     assert((cast(size_t)x.ptr & 15) == 0); 
    890     assert(gc_sizeOf(x.ptr) > x.length * sizeelem); 
    891     return x; 
     1296version(none) 
     1297
     1298    // no clue why this was special cased... 
     1299    extern (C) byte[] _d_arrayappendcT(TypeInfo ti, ref byte[] x, ...) 
     1300    { 
     1301        auto sizeelem = ti.next.tsize();            // array element size 
     1302        auto info = gc_query(x.ptr); 
     1303        auto length = x.length; 
     1304        auto newlength = length + 1; 
     1305        auto newsize = newlength * sizeelem; 
     1306 
     1307        assert(info.size == 0 || length * sizeelem <= info.size); 
     1308 
     1309        debug(PRINTF) printf("_d_arrayappendcT(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size); 
     1310 
     1311        if (info.size <= newsize || info.base != x.ptr) 
     1312        {   byte* newdata; 
     1313 
     1314            if (info.size >= PAGESIZE && info.base == x.ptr) 
     1315            {   // Try to extend in-place 
     1316                auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size); 
     1317                if (u) 
     1318                { 
     1319                    goto L1; 
     1320                } 
     1321            } 
     1322            debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size); 
     1323            auto newcap = newCapacity(newlength, sizeelem); 
     1324            assert(newcap >= newlength * sizeelem); 
     1325            newdata = cast(byte *)gc_malloc(newcap + 1, info.attr); 
     1326            memcpy(newdata, x.ptr, length * sizeelem); 
     1327            (cast(void**)(&x))[1] = newdata; 
     1328        } 
     1329L1: 
     1330        byte *argp = cast(byte *)(&ti + 2); 
     1331 
     1332        *cast(size_t *)&x = newlength; 
     1333        x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem]; 
     1334        assert((cast(size_t)x.ptr & 15) == 0); 
     1335        assert(gc_sizeOf(x.ptr) > x.length * sizeelem); 
     1336        return x; 
     1337    } 
     1338
     1339else 
     1340
     1341    extern (C) long _d_arrayappendcT(TypeInfo ti, Array *x, ...) 
     1342    { 
     1343        byte *argp = cast(byte*)(&ti + 2); 
     1344        return _d_arrayappendT(ti, x, argp[0..1]); 
     1345    } 
    8921346} 
    8931347 
    8941348 
    8951349/** 
    8961350 * Append dchar to char[] 
    8971351 */ 
    898 extern (C) char[] _d_arrayappendcd(ref char[] x, dchar c) 
    899 
    900     const sizeelem = c.sizeof;            // array element size 
    901     auto info = gc_query(x.ptr); 
    902     auto length = x.length; 
    903  
     1352extern (C) long _d_arrayappendcd(ref char[] x, dchar c) 
     1353
    9041354    // c could encode into from 1 to 4 characters 
    905     int nchars; 
     1355    char[4] buf = void; 
     1356    byte[] appendthis; // passed to appendT 
    9061357    if (c <= 0x7F) 
    907         nchars = 1; 
     1358    { 
     1359        buf.ptr[0] = cast(char)c; 
     1360        appendthis = (cast(byte *)buf.ptr)[0..1]; 
     1361    } 
    9081362    else if (c <= 0x7FF) 
    909         nchars = 2; 
     1363    { 
     1364        buf.ptr[0] = cast(char)(0xC0 | (c >> 6)); 
     1365        buf.ptr[1] = cast(char)(0x80 | (c & 0x3F)); 
     1366        appendthis = (cast(byte *)buf.ptr)[0..2]; 
     1367    } 
    9101368    else if (c <= 0xFFFF) 
    911         nchars = 3; 
     1369    { 
     1370        buf.ptr[0] = cast(char)(0xE0 | (c >> 12)); 
     1371        buf.ptr[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); 
     1372        buf.ptr[2] = cast(char)(0x80 | (c & 0x3F)); 
     1373        appendthis = (cast(byte *)buf.ptr)[0..3]; 
     1374    } 
    9121375    else if (c <= 0x10FFFF) 
    913         nchars = 4; 
     1376    { 
     1377        buf.ptr[0] = cast(char)(0xF0 | (c >> 18)); 
     1378        buf.ptr[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); 
     1379        buf.ptr[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); 
     1380        buf.ptr[3] = cast(char)(0x80 | (c & 0x3F)); 
     1381        appendthis = (cast(byte *)buf.ptr)[0..4]; 
     1382    } 
    9141383    else 
    9151384    assert(0);  // invalid utf character - should we throw an exception instead? 
    9161385 
    917     auto newlength = length + nchars; 
    918     auto newsize = newlength * sizeelem; 
    919  
    920     assert(info.size == 0 || length * sizeelem <= info.size); 
    921  
    922     debug(PRINTF) printf("_d_arrayappendcd(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size); 
    923  
    924     if (info.size <= newsize || info.base != x.ptr) 
    925     {   byte* newdata; 
    926  
    927         if (info.size >= PAGESIZE && info.base == x.ptr) 
    928         {   // Try to extend in-place 
    929             auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size); 
    930             if (u) 
    931             { 
    932                 goto L1; 
    933             } 
    934         } 
    935         debug(PRINTF) printf("_d_arrayappendcd(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size); 
    936         auto newcap = newCapacity(newlength, sizeelem); 
    937         assert(newcap >= newlength * sizeelem); 
    938         newdata = cast(byte *)gc_malloc(newcap + 1, info.attr); 
    939         memcpy(newdata, x.ptr, length * sizeelem); 
    940         (cast(void**)(&x))[1] = newdata; 
    941     } 
    942   L1: 
    943     *cast(size_t *)&x = newlength; 
    944     char* ptr = &x.ptr[length]; 
    945  
    946     if (c <= 0x7F) 
    947     { 
    948         ptr[0] = cast(char) c; 
    949     } 
    950     else if (c <= 0x7FF) 
    951     { 
    952         ptr[0] = cast(char)(0xC0 | (c >> 6)); 
    953         ptr[1] = cast(char)(0x80 | (c & 0x3F)); 
    954     } 
    955     else if (c <= 0xFFFF) 
    956     { 
    957         ptr[0] = cast(char)(0xE0 | (c >> 12)); 
    958         ptr[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); 
    959         ptr[2] = cast(char)(0x80 | (c & 0x3F)); 
    960     } 
    961     else if (c <= 0x10FFFF) 
    962     { 
    963         ptr[0] = cast(char)(0xF0 | (c >> 18)); 
    964         ptr[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); 
    965         ptr[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); 
    966         ptr[3] = cast(char)(0x80 | (c & 0x3F)); 
     1386    // 
     1387    // TODO: This always assumes the array type is shared, because we do not 
     1388    // get a typeinfo from the compiler.  Assuming shared is the safest option. 
     1389    // Once the compiler is fixed, the proper typeinfo should be forwarded. 
     1390    // 
     1391    return _d_arrayappendT(typeid(shared char[]), cast(Array *)&x, appendthis); 
     1392
     1393 
     1394 
     1395/** 
     1396 * Append dchar to wchar[] 
     1397 */ 
     1398extern (C) long _d_arrayappendwd(ref wchar[] x, dchar c) 
     1399
     1400    // c could encode into from 1 to 2 w characters 
     1401    wchar[2] buf = void; 
     1402    byte[] appendthis; // passed to appendT 
     1403    if (c <= 0xFFFF) 
     1404    { 
     1405        buf.ptr[0] = cast(wchar) c; 
     1406        // note that although we are passing only 1 byte here, appendT 
     1407        // interprets this as being an array of wchar, making the necessary 
     1408        // casts. 
     1409        appendthis = (cast(byte *)buf.ptr)[0..1]; 
    9671410    } 
    9681411    else 
    969     assert(0); 
    970  
    971     assert((cast(size_t)x.ptr & 15) == 0); 
    972     assert(gc_sizeOf(x.ptr) > x.length * sizeelem); 
    973     return x; 
    974 
    975  
    976  
    977 /** 
    978  * Append dchar to wchar[] 
    979  */ 
    980 extern (C) wchar[] _d_arrayappendwd(ref wchar[] x, dchar c) 
    981 
    982     const sizeelem = c.sizeof;            // array element size 
    983     auto info = gc_query(x.ptr); 
    984     auto length = x.length; 
    985  
    986     // c could encode into from 1 to 2 w characters 
    987     int nchars; 
    988     if (c <= 0xFFFF) 
    989         nchars = 1; 
    990     else 
    991         nchars = 2; 
    992  
    993     auto newlength = length + nchars; 
    994     auto newsize = newlength * sizeelem; 
    995  
    996     assert(info.size == 0 || length * sizeelem <= info.size); 
    997  
    998     debug(PRINTF) printf("_d_arrayappendwd(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size); 
    999  
    1000     if (info.size <= newsize || info.base != x.ptr) 
    1001     {   byte* newdata; 
    1002  
    1003         if (info.size >= PAGESIZE && info.base == x.ptr) 
    1004         {   // Try to extend in-place 
    1005             auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size); 
    1006             if (u) 
    1007             { 
    1008                 goto L1; 
    1009             } 
    1010         } 
    1011         debug(PRINTF) printf("_d_arrayappendwd(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size); 
    1012         auto newcap = newCapacity(newlength, sizeelem); 
    1013         assert(newcap >= newlength * sizeelem); 
    1014         newdata = cast(byte *)gc_malloc(newcap + 1, info.attr); 
    1015         memcpy(newdata, x.ptr, length * sizeelem); 
    1016         (cast(void**)(&x))[1] = newdata; 
    1017     } 
    1018   L1: 
    1019     *cast(size_t *)&x = newlength; 
    1020     wchar* ptr = &x.ptr[length]; 
    1021  
    1022     if (c <= 0xFFFF) 
    1023     { 
    1024         ptr[0] = cast(wchar) c; 
    1025     } 
    1026     else 
    1027     { 
    1028     ptr[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); 
    1029     ptr[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); 
    1030     } 
    1031  
    1032     assert((cast(size_t)x.ptr & 15) == 0); 
    1033     assert(gc_sizeOf(x.ptr) > x.length * sizeelem); 
    1034     return x; 
     1412    { 
     1413    buf.ptr[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); 
     1414    buf.ptr[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); 
     1415        // ditto from above. 
     1416        appendthis = (cast(byte *)buf.ptr)[0..2]; 
     1417    } 
     1418 
     1419    // 
     1420    // TODO: This always assumes the array type is shared, because we do not 
     1421    // get a typeinfo from the compiler.  Assuming shared is the safest option. 
     1422    // Once the compiler is fixed, the proper typeinfo should be forwarded. 
     1423    // 
     1424    return _d_arrayappendT(typeid(shared wchar[]), cast(Array *)&x, appendthis); 
    10351425} 
    10361426 
    10371427 
    10381428/** 
    10391429 * 
    10401430 */ 
    10411431extern (C) byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y) 
    10421432out (result) 
    10431433{ 
    10441434    auto sizeelem = ti.next.tsize();            // array element size 
     
    10721462    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr); 
    10731463    auto sizeelem = ti.next.tsize();            // array element size 
    10741464    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem); 
    10751465    size_t xlen = x.length * sizeelem; 
    10761466    size_t ylen = y.length * sizeelem; 
    10771467    size_t len  = xlen + ylen; 
    10781468 
    10791469    if (!len) 
    10801470        return null; 
    10811471 
    1082     byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1472    auto info = gc_malloc_bi(len + __arrayPad(len), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1473    byte* p = cast(byte*)__arrayStart(info); 
     1474    p[len] = 0; // guessing this is to optimize for null-terminated arrays? 
    10831475    memcpy(p, x.ptr, xlen); 
    10841476    memcpy(p + xlen, y.ptr, ylen); 
    1085     p[len] = 0; 
     1477    auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     1478    __setArrayAllocLength(info, len, isshared); 
    10861479    return p[0 .. x.length + y.length]; 
    10871480} 
    10881481 
    10891482 
    10901483/** 
    10911484 * 
    10921485 */ 
    10931486extern (C) byte[] _d_arraycatnT(TypeInfo ti, uint n, ...) 
    10941487{   void* a; 
    10951488    size_t length; 
     
    11011494    p = cast(byte[]*)(&n + 1); 
    11021495 
    11031496    for (i = 0; i < n; i++) 
    11041497    { 
    11051498        b = *p++; 
    11061499        length += b.length; 
    11071500    } 
    11081501    if (!length) 
    11091502        return null; 
    11101503 
    1111     a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1504    auto allocsize = length * size; 
     1505    auto info = gc_malloc_bi(allocsize + __arrayPad(allocsize), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1506    auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     1507    __setArrayAllocLength(info, allocsize, isshared); 
     1508    a = __arrayStart(info); 
    11121509    p = cast(byte[]*)(&n + 1); 
    11131510 
    11141511    uint j = 0; 
    11151512    for (i = 0; i < n; i++) 
    11161513    { 
    11171514        b = *p++; 
    11181515        if (b.length) 
    11191516        { 
    11201517            memcpy(a + j, b.ptr, b.length * size); 
    11211518            j += b.length * size; 
     
    11351532extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...) 
    11361533{ 
    11371534    auto sizeelem = ti.next.tsize();            // array element size 
    11381535    void* result; 
    11391536 
    11401537    debug(PRINTF) printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length); 
    11411538    if (length == 0 || sizeelem == 0) 
    11421539        result = null; 
    11431540    else 
    11441541    { 
    1145         result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1542        auto allocsize = length * sizeelem; 
     1543        auto info = gc_malloc_bi(allocsize + __arrayPad(allocsize), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1544        auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     1545        __setArrayAllocLength(info, allocsize, isshared); 
     1546        result = __arrayStart(info); 
    11461547 
    11471548        va_list q; 
    11481549        va_start!(size_t)(q, length); 
    11491550 
    11501551        size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1); 
    11511552 
    11521553        if (stacksize == sizeelem) 
    11531554        { 
    11541555            memcpy(result, q, length * sizeelem); 
    11551556        } 
     
    11881589    assert(memcmp((*cast(Array2*)&result).ptr, a.ptr, a.length * sizeelem) == 0); 
    11891590} 
    11901591body 
    11911592{ 
    11921593    Array2 r; 
    11931594 
    11941595    if (a.length) 
    11951596    { 
    11961597        auto sizeelem = ti.next.tsize();                // array element size 
    11971598        auto size = a.length * sizeelem; 
    1198         r.ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1599        auto info = gc_malloc_bi(size + __arrayPad(size), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
     1600        auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
     1601        __setArrayAllocLength(info, size, isshared); 
     1602        r.ptr = __arrayStart(info); 
    11991603        r.length = a.length; 
    12001604        memcpy(r.ptr, a.ptr, size); 
    12011605    } 
    12021606    return *cast(long*)(&r); 
    12031607} 
    12041608 
    12051609 
    12061610unittest 
    12071611{ 
    12081612    int[] a;