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

Changeset 328

Show
Ignore:
Timestamp:
07/13/10 14:45:45 (14 years ago)
Author:
schveiguy
Message:

Remove ghost length from allocating a new object, I will flag such objects as not appendable.
Change prefix pad on large blocks to 16 bytes instead of 8, made the size configurable (see bug 4400)

Files:

Legend:

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

    r327 r328  
    2222    import core.stdc.string; 
    2323    import core.stdc.stdarg; 
    2424    debug(PRINTF) import core.stdc.stdio; 
    2525} 
    2626 
    2727 
    2828private 
    2929{ 
    3030    enum BlkAttr : uint 
    3131    { 
    32         FINALIZE = 0b0000_0001, 
    33         NO_SCAN  = 0b0000_0010, 
    34         NO_MOVE  = 0b0000_0100, 
    35         ALL_BITS = 0b1111_1111 
     32        FINALIZE   = 0b0000_0001, 
     33        NO_SCAN    = 0b0000_0010, 
     34        NO_MOVE    = 0b0000_0100, 
     35        APPENDABLE = 0b0000_1000, 
     36        ALL_BITS   = 0b1111_1111 
    3637    } 
    3738 
    3839    struct BlkInfo 
    3940    { 
    4041        void*  base; 
    4142        size_t size; 
    4243        uint   attr; 
    4344    } 
    4445 
    4546    extern (C) uint gc_getAttr( in void* p ); 
     
    6768    } 
    6869 
    6970    alias bool function(Object) CollectHandler; 
    7071    __gshared CollectHandler collectHandler = null; 
    7172 
    7273enum : size_t 
    7374       { 
    7475           BIGLENGTHMASK = ~(cast(size_t)PAGESIZE - 1), 
    7576           SMALLPAD = 1, 
    7677           MEDPAD = ushort.sizeof, 
    77            LARGEPAD = size_t.sizeof * 2 + 1, 
     78           LARGEPREFIX = 16, // 16 bytes padding at the front of the array 
     79           LARGEPAD = LARGEPREFIX + 1, 
    7880           MAXSMALLSIZE = 256-SMALLPAD, 
    7981           MAXMEDSIZE = (PAGESIZE / 2) - MEDPAD 
    8082       } 
    8183} 
    8284 
    8385 
    8486/** 
    8587 * 
    8688 */ 
    8789extern (C) void* _d_allocmemory(size_t sz) 
     
    108110        if (!p) 
    109111            onOutOfMemoryError(); 
    110112    } 
    111113    else 
    112114    { 
    113115        auto info = gc_qalloc(ci.init.length + __arrayPad(ci.init.length), 
    114116                      BlkAttr.FINALIZE | (ci.m_flags & 2 ? BlkAttr.NO_SCAN : 0)); 
    115117        p = info.base; 
    116118        // only init ghost array length if noscan is set.  Scanned blocks are 
    117119        // initialized to 0 by the gc. 
    118         if(ci.flags & 2) 
    119         { 
    120             // initialize the ghost array length at the end of the block.  This 
    121             // prevents accidental stomping in the case where a class contains 
    122             // a static array and someone tries to append to a slice of that 
    123             // array. 
    124             *((cast(size_t *)(p + info.size)) - 1) = 0; 
    125         } 
    126120        debug(PRINTF) printf(" p = %p\n", p); 
    127121    } 
    128122 
    129123    debug(PRINTF) 
    130124    { 
    131125        printf("p = %p\n", p); 
    132126        printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length); 
    133127        printf("vptr = %p\n", *cast(void**) ci.init); 
    134128        printf("vtbl[0] = %p\n", (*cast(void***) ci.init)[0]); 
    135129        printf("vtbl[1] = %p\n", (*cast(void***) ci.init)[1]); 
     
    221215 
    222216  a block with 512 to pagesize/2 bytes has a 16-bit length. 
    223217 
    224218  For blocks >= pagesize, the length is a size_t and is at the beginning of the 
    225219  block.  The reason we have to do this is because the block can extend into 
    226220  more pages, so we cannot trust the block length if it sits at the end of the 
    227221  block, because it might have just been extended.  If we can prove in the 
    228222  future that the block is unshared, we may be able to change this, but I'm not 
    229223  sure it's important. 
    230224 
    231   In order to do put the length at the front, we have to provide 2*size_t bytes 
    232   buffer space in case the block has to be aligned properly.  For example, on a 
    233   32-bit OS, doubles should be 8-byte aligned.  In addition, we need the 
    234   sentinel byte to prevent accidental pointers to the next block.  Because of 
    235   the extra overhead, we only do this for page size and above, where th
    236   overhead is minimal compared to the block size. 
     225  In order to do put the length at the front, we have to provide 16 bytes 
     226  buffer space in case the block has to be aligned properly.  In x86, certain 
     227  SSE instructions will only work if the data is 16-byte aligned.  In addition, 
     228  we need the sentinel byte to prevent accidental pointers to the next block. 
     229  Because of the extra overhead, we only do this for page size and above, wher
     230  the overhead is minimal compared to the block size. 
    237231 
    238232  So for those blocks, it looks like: 
    239233 
    240234  |N*elemsize|padding|elem0|elem1|...|elemN-1|emptyspace|sentinelbyte| 
    241235 
    242   where elem0 starts 8 bytes after the first byte. 
     236  where elem0 starts 16 bytes after the first byte. 
    243237  */ 
    244238bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, size_t oldlength = ~0) 
    245239{ 
    246240    if(info.size <= 256) 
    247241    { 
    248242        if(newlength + SMALLPAD > info.size) 
    249243            // new size does not fit inside block 
    250244            return false; 
    251245        auto length = cast(ubyte *)(info.base + info.size - SMALLPAD); 
    252246        if(oldlength != ~0) 
     
    340334        } 
    341335    } 
    342336    return true; // resize succeeded 
    343337} 
    344338 
    345339/** 
    346340  get the start of the array for the given block 
    347341  */ 
    348342void *__arrayStart(BlkInfo info) 
    349343{ 
    350     return info.base + ((info.size & BIGLENGTHMASK) ? 2*size_t.sizeof : 0); 
     344    return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0); 
    351345} 
    352346 
    353347/** 
    354348  get the padding required to allocate size bytes.  Note that the padding is 
    355349  NOT included in the passed in size.  Therefore, do NOT call this function 
    356350  with the size of an allocated block. 
    357351  */ 
    358352size_t __arrayPad(size_t size) 
    359353{ 
    360354    return size > MAXMEDSIZE ? LARGEPAD : (size > MAXSMALLSIZE ? MEDPAD : SMALLPAD); 
     
    484478    // note, we do not care about shared.  We are setting the length no matter 
    485479    // what, so no lock is required. 
    486480    debug(PRINTF) printf("_d_arrayshrinkfit, elemsize = %d, arr.ptr = x%x arr.length = %d\n", ti.next.tsize(), arr.ptr, arr.length); 
    487481    auto size = ti.next.tsize();                // array element size 
    488482    auto cursize = arr.length * size; 
    489483    auto   bic = __getBlkInfo(arr.ptr); 
    490484    auto   info = bic ? *bic : gc_query(arr.ptr); 
    491485    if(info.base) 
    492486    { 
    493487        if(info.size >= PAGESIZE) 
    494             // remove 4 from the current size 
    495             cursize -= (size_t.sizeof) * 2
     488            // remove prefix from the current stored size 
     489            cursize -= LARGEPREFIX
    496490        debug(PRINTF) printf("setting allocated size to %d\n", (arr.ptr - info.base) + cursize); 
    497491        __setArrayAllocLength(info, (arr.ptr - info.base) + cursize, false); 
    498492    } 
    499493} 
    500494 
    501495/** 
    502496 * set the array capacity.  If the array capacity isn't currently large enough 
    503497 * to hold the requested capacity (in number of elements), then the array is 
    504498 * resized/reallocated to the appropriate size.  Pass in a requested capacity 
    505499 * of 0 to get the current capacity.  Returns the number of elements that can 
     
    634628    p.data = cast(byte *)tgt; 
    635629 
    636630    // determine the padding.  This has to be done manually because __arrayPad 
    637631    // assumes you are not counting the pad size, and info.size does include 
    638632    // the pad. 
    639633    if(info.size <= 256) 
    640634        arraypad = SMALLPAD; 
    641635    else if(info.size < PAGESIZE) 
    642636        arraypad = MEDPAD; 
    643637    else 
    644         arraypad = SMALLPAD; 
     638        arraypad = LARGEPAD; 
    645639 
    646640    curcapacity = info.size - arraypad; 
    647641    return curcapacity / size; 
    648642 
    649643Loverflow: 
    650644    onOutOfMemoryError(); 
    651645} 
    652646 
    653647/** 
    654648 * Allocate a new array of length elements. 
     
    670664            asm 
    671665            { 
    672666                mov     EAX,size        ; 
    673667                mul     EAX,length      ; 
    674668                mov     size,EAX        ; 
    675669                jc      Loverflow       ; 
    676670            } 
    677671        } 
    678672        else 
    679673            size *= length; 
    680         // increase the size by 1 if the actual requested size is < 256, 
    681         // by size_t.sizeof if it's >= 256 
    682          
     674        // increase the size by the array pad. 
    683675        auto info = gc_qalloc(size + __arrayPad(size), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 
    684676        debug(PRINTF) printf(" p = %p\n", info.base); 
    685677        // update the length of the array 
    686678        auto arrstart = __arrayStart(info); 
    687679        memset(arrstart, 0, size); 
    688680        auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 
    689681        __setArrayAllocLength(info, size, isshared); 
    690682        result = cast(ulong)length + (cast(ulong)cast(size_t)arrstart << 32); 
    691683    } 
    692684    return result; 
     
    11161108                                    goto L1; 
    11171109                                } 
    11181110                            } 
    11191111                        } 
    11201112 
    11211113                        // couldn't do it, reallocate 
    11221114                        info = gc_qalloc(newsize + LARGEPAD, info.attr); 
    11231115                        __setArrayAllocLength(info, newsize, isshared); 
    11241116                        if(!isshared) 
    11251117                            __insertBlkInfoCache(info, bic); 
    1126                         newdata = cast(byte *)(info.base + size_t.sizeof * 2); 
     1118                        newdata = cast(byte *)(info.base + LARGEPREFIX); 
    11271119                        newdata[0 .. size] = p.data[0 .. size]; 
    11281120                    } 
    11291121                } 
    11301122                else if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
    11311123                { 
    11321124                    // could not resize in place 
    11331125                    info = gc_qalloc(newsize + __arrayPad(newsize), info.attr); 
    11341126                    __setArrayAllocLength(info, newsize, isshared); 
    11351127                    if(!isshared) 
    11361128                        __insertBlkInfoCache(info, bic); 
     
    12631255                                    goto L1; 
    12641256                                } 
    12651257                            } 
    12661258                        } 
    12671259 
    12681260                        // couldn't do it, reallocate 
    12691261                        info = gc_qalloc(newsize + LARGEPAD, info.attr); 
    12701262                        __setArrayAllocLength(info, newsize, isshared); 
    12711263                        if(!isshared) 
    12721264                            __insertBlkInfoCache(info, bic); 
    1273                         newdata = cast(byte *)(info.base + size_t.sizeof * 2); 
     1265                        newdata = cast(byte *)(info.base + LARGEPREFIX); 
    12741266                        newdata[0 .. size] = p.data[0 .. size]; 
    12751267                    } 
    12761268                } 
    12771269                else if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
    12781270                { 
    12791271                    // could not resize in place 
    12801272                    info = gc_qalloc(newsize + __arrayPad(newsize), info.attr); 
    12811273                    __setArrayAllocLength(info, newsize, isshared); 
    12821274                    if(!isshared) 
    12831275                        __insertBlkInfoCache(info, bic); 
     
    13761368                        goto L1; 
    13771369                    } 
    13781370                } 
    13791371            } 
    13801372 
    13811373            // couldn't do it, reallocate 
    13821374            info = gc_qalloc(newCapacity(newlength, sizeelem) + LARGEPAD, info.attr); 
    13831375            __setArrayAllocLength(info, newsize, isshared); 
    13841376            if(!isshared) 
    13851377                __insertBlkInfoCache(info, bic); 
    1386             auto newdata = cast(byte *)info.base + size_t.sizeof * 2
     1378            auto newdata = cast(byte *)info.base + LARGEPREFIX
    13871379            memcpy(newdata, px.data, length * sizeelem); 
    13881380            px.data = newdata; 
    13891381        } 
    13901382    } 
    13911383    else if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 
    13921384    { 
    13931385        // could not resize in place 
    13941386        auto allocsize = newCapacity(newlength, sizeelem); 
    13951387        info = gc_qalloc(allocsize + __arrayPad(allocsize), info.attr); 
    13961388        __setArrayAllocLength(info, newsize, isshared); 
  • trunk/src/unittest.d

    r286 r328  
    1212public import core.sync.semaphore; 
    1313 
    1414 
    1515void main() 
    1616{ 
    1717    // Bring in unit test for module by referencing a function in it 
    1818    shared(int) i; 
    1919    cas( &i, i.init, i.init + 1 ); // atomic 
    2020    bsf( 0 ); // bitop 
    2121    setAssertHandler( null ); // exception 
    22     GC.enable(); // memory 
     22    // SES - disabled because you cannot enable the GC without disabling it. 
     23    //GC.enable(); // memory 
    2324    Runtime.collectHandler = null; // runtime 
    2425    static void fn() {} 
    2526    new Thread( &fn ); // thread 
    2627    va_end( null ); // vararg 
    2728 
    2829    auto m = new Mutex; // mutex 
    2930    auto c = new Condition( m ); // condition 
    3031    auto r = new ReadWriteMutex; // rwmutex 
    3132    auto s = new Semaphore; // semaphore 
    3233}