Changeset 328
- Timestamp:
- 07/13/10 14:45:45 (14 years ago)
- Files:
-
- trunk/src/rt/lifetime.d (modified) (11 diffs)
- trunk/src/unittest.d (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/src/rt/lifetime.d
r327 r328 22 22 import core.stdc.string; 23 23 import core.stdc.stdarg; 24 24 debug(PRINTF) import core.stdc.stdio; 25 25 } 26 26 27 27 28 28 private 29 29 { 30 30 enum BlkAttr : uint 31 31 { 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 36 37 } 37 38 38 39 struct BlkInfo 39 40 { 40 41 void* base; 41 42 size_t size; 42 43 uint attr; 43 44 } 44 45 45 46 extern (C) uint gc_getAttr( in void* p ); … … 67 68 } 68 69 69 70 alias bool function(Object) CollectHandler; 70 71 __gshared CollectHandler collectHandler = null; 71 72 72 73 enum : size_t 73 74 { 74 75 BIGLENGTHMASK = ~(cast(size_t)PAGESIZE - 1), 75 76 SMALLPAD = 1, 76 77 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, 78 80 MAXSMALLSIZE = 256-SMALLPAD, 79 81 MAXMEDSIZE = (PAGESIZE / 2) - MEDPAD 80 82 } 81 83 } 82 84 83 85 84 86 /** 85 87 * 86 88 */ 87 89 extern (C) void* _d_allocmemory(size_t sz) … … 108 110 if (!p) 109 111 onOutOfMemoryError(); 110 112 } 111 113 else 112 114 { 113 115 auto info = gc_qalloc(ci.init.length + __arrayPad(ci.init.length), 114 116 BlkAttr.FINALIZE | (ci.m_flags & 2 ? BlkAttr.NO_SCAN : 0)); 115 117 p = info.base; 116 118 // only init ghost array length if noscan is set. Scanned blocks are 117 119 // initialized to 0 by the gc. 118 if(ci.flags & 2)119 {120 // initialize the ghost array length at the end of the block. This121 // prevents accidental stomping in the case where a class contains122 // a static array and someone tries to append to a slice of that123 // array.124 *((cast(size_t *)(p + info.size)) - 1) = 0;125 }126 120 debug(PRINTF) printf(" p = %p\n", p); 127 121 } 128 122 129 123 debug(PRINTF) 130 124 { 131 125 printf("p = %p\n", p); 132 126 printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length); 133 127 printf("vptr = %p\n", *cast(void**) ci.init); 134 128 printf("vtbl[0] = %p\n", (*cast(void***) ci.init)[0]); 135 129 printf("vtbl[1] = %p\n", (*cast(void***) ci.init)[1]); … … 221 215 222 216 a block with 512 to pagesize/2 bytes has a 16-bit length. 223 217 224 218 For blocks >= pagesize, the length is a size_t and is at the beginning of the 225 219 block. The reason we have to do this is because the block can extend into 226 220 more pages, so we cannot trust the block length if it sits at the end of the 227 221 block, because it might have just been extended. If we can prove in the 228 222 future that the block is unshared, we may be able to change this, but I'm not 229 223 sure it's important. 230 224 231 In order to do put the length at the front, we have to provide 2*size_tbytes232 buffer space in case the block has to be aligned properly. For example, on a233 32-bit OS, doubles should be 8-byte aligned. In addition, we need the234 sentinel byte to prevent accidental pointers to the next block. Because of235 the extra overhead, we only do this for page size and above, where the236 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, where 230 the overhead is minimal compared to the block size. 237 231 238 232 So for those blocks, it looks like: 239 233 240 234 |N*elemsize|padding|elem0|elem1|...|elemN-1|emptyspace|sentinelbyte| 241 235 242 where elem0 starts 8bytes after the first byte.236 where elem0 starts 16 bytes after the first byte. 243 237 */ 244 238 bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, size_t oldlength = ~0) 245 239 { 246 240 if(info.size <= 256) 247 241 { 248 242 if(newlength + SMALLPAD > info.size) 249 243 // new size does not fit inside block 250 244 return false; 251 245 auto length = cast(ubyte *)(info.base + info.size - SMALLPAD); 252 246 if(oldlength != ~0) … … 340 334 } 341 335 } 342 336 return true; // resize succeeded 343 337 } 344 338 345 339 /** 346 340 get the start of the array for the given block 347 341 */ 348 342 void *__arrayStart(BlkInfo info) 349 343 { 350 return info.base + ((info.size & BIGLENGTHMASK) ? 2*size_t.sizeof: 0);344 return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0); 351 345 } 352 346 353 347 /** 354 348 get the padding required to allocate size bytes. Note that the padding is 355 349 NOT included in the passed in size. Therefore, do NOT call this function 356 350 with the size of an allocated block. 357 351 */ 358 352 size_t __arrayPad(size_t size) 359 353 { 360 354 return size > MAXMEDSIZE ? LARGEPAD : (size > MAXSMALLSIZE ? MEDPAD : SMALLPAD); … … 484 478 // note, we do not care about shared. We are setting the length no matter 485 479 // what, so no lock is required. 486 480 debug(PRINTF) printf("_d_arrayshrinkfit, elemsize = %d, arr.ptr = x%x arr.length = %d\n", ti.next.tsize(), arr.ptr, arr.length); 487 481 auto size = ti.next.tsize(); // array element size 488 482 auto cursize = arr.length * size; 489 483 auto bic = __getBlkInfo(arr.ptr); 490 484 auto info = bic ? *bic : gc_query(arr.ptr); 491 485 if(info.base) 492 486 { 493 487 if(info.size >= PAGESIZE) 494 // remove 4 from the currentsize495 cursize -= (size_t.sizeof) * 2;488 // remove prefix from the current stored size 489 cursize -= LARGEPREFIX; 496 490 debug(PRINTF) printf("setting allocated size to %d\n", (arr.ptr - info.base) + cursize); 497 491 __setArrayAllocLength(info, (arr.ptr - info.base) + cursize, false); 498 492 } 499 493 } 500 494 501 495 /** 502 496 * set the array capacity. If the array capacity isn't currently large enough 503 497 * to hold the requested capacity (in number of elements), then the array is 504 498 * resized/reallocated to the appropriate size. Pass in a requested capacity 505 499 * of 0 to get the current capacity. Returns the number of elements that can … … 634 628 p.data = cast(byte *)tgt; 635 629 636 630 // determine the padding. This has to be done manually because __arrayPad 637 631 // assumes you are not counting the pad size, and info.size does include 638 632 // the pad. 639 633 if(info.size <= 256) 640 634 arraypad = SMALLPAD; 641 635 else if(info.size < PAGESIZE) 642 636 arraypad = MEDPAD; 643 637 else 644 arraypad = SMALLPAD;638 arraypad = LARGEPAD; 645 639 646 640 curcapacity = info.size - arraypad; 647 641 return curcapacity / size; 648 642 649 643 Loverflow: 650 644 onOutOfMemoryError(); 651 645 } 652 646 653 647 /** 654 648 * Allocate a new array of length elements. … … 670 664 asm 671 665 { 672 666 mov EAX,size ; 673 667 mul EAX,length ; 674 668 mov size,EAX ; 675 669 jc Loverflow ; 676 670 } 677 671 } 678 672 else 679 673 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. 683 675 auto info = gc_qalloc(size + __arrayPad(size), !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); 684 676 debug(PRINTF) printf(" p = %p\n", info.base); 685 677 // update the length of the array 686 678 auto arrstart = __arrayStart(info); 687 679 memset(arrstart, 0, size); 688 680 auto isshared = ti.classinfo is TypeInfo_Shared.classinfo; 689 681 __setArrayAllocLength(info, size, isshared); 690 682 result = cast(ulong)length + (cast(ulong)cast(size_t)arrstart << 32); 691 683 } 692 684 return result; … … 1116 1108 goto L1; 1117 1109 } 1118 1110 } 1119 1111 } 1120 1112 1121 1113 // couldn't do it, reallocate 1122 1114 info = gc_qalloc(newsize + LARGEPAD, info.attr); 1123 1115 __setArrayAllocLength(info, newsize, isshared); 1124 1116 if(!isshared) 1125 1117 __insertBlkInfoCache(info, bic); 1126 newdata = cast(byte *)(info.base + size_t.sizeof * 2);1118 newdata = cast(byte *)(info.base + LARGEPREFIX); 1127 1119 newdata[0 .. size] = p.data[0 .. size]; 1128 1120 } 1129 1121 } 1130 1122 else if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 1131 1123 { 1132 1124 // could not resize in place 1133 1125 info = gc_qalloc(newsize + __arrayPad(newsize), info.attr); 1134 1126 __setArrayAllocLength(info, newsize, isshared); 1135 1127 if(!isshared) 1136 1128 __insertBlkInfoCache(info, bic); … … 1263 1255 goto L1; 1264 1256 } 1265 1257 } 1266 1258 } 1267 1259 1268 1260 // couldn't do it, reallocate 1269 1261 info = gc_qalloc(newsize + LARGEPAD, info.attr); 1270 1262 __setArrayAllocLength(info, newsize, isshared); 1271 1263 if(!isshared) 1272 1264 __insertBlkInfoCache(info, bic); 1273 newdata = cast(byte *)(info.base + size_t.sizeof * 2);1265 newdata = cast(byte *)(info.base + LARGEPREFIX); 1274 1266 newdata[0 .. size] = p.data[0 .. size]; 1275 1267 } 1276 1268 } 1277 1269 else if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 1278 1270 { 1279 1271 // could not resize in place 1280 1272 info = gc_qalloc(newsize + __arrayPad(newsize), info.attr); 1281 1273 __setArrayAllocLength(info, newsize, isshared); 1282 1274 if(!isshared) 1283 1275 __insertBlkInfoCache(info, bic); … … 1376 1368 goto L1; 1377 1369 } 1378 1370 } 1379 1371 } 1380 1372 1381 1373 // couldn't do it, reallocate 1382 1374 info = gc_qalloc(newCapacity(newlength, sizeelem) + LARGEPAD, info.attr); 1383 1375 __setArrayAllocLength(info, newsize, isshared); 1384 1376 if(!isshared) 1385 1377 __insertBlkInfoCache(info, bic); 1386 auto newdata = cast(byte *)info.base + size_t.sizeof * 2;1378 auto newdata = cast(byte *)info.base + LARGEPREFIX; 1387 1379 memcpy(newdata, px.data, length * sizeelem); 1388 1380 px.data = newdata; 1389 1381 } 1390 1382 } 1391 1383 else if(!__setArrayAllocLength(info, newsize + offset, isshared, size + offset)) 1392 1384 { 1393 1385 // could not resize in place 1394 1386 auto allocsize = newCapacity(newlength, sizeelem); 1395 1387 info = gc_qalloc(allocsize + __arrayPad(allocsize), info.attr); 1396 1388 __setArrayAllocLength(info, newsize, isshared); trunk/src/unittest.d
r286 r328 12 12 public import core.sync.semaphore; 13 13 14 14 15 15 void main() 16 16 { 17 17 // Bring in unit test for module by referencing a function in it 18 18 shared(int) i; 19 19 cas( &i, i.init, i.init + 1 ); // atomic 20 20 bsf( 0 ); // bitop 21 21 setAssertHandler( null ); // exception 22 GC.enable(); // memory 22 // SES - disabled because you cannot enable the GC without disabling it. 23 //GC.enable(); // memory 23 24 Runtime.collectHandler = null; // runtime 24 25 static void fn() {} 25 26 new Thread( &fn ); // thread 26 27 va_end( null ); // vararg 27 28 28 29 auto m = new Mutex; // mutex 29 30 auto c = new Condition( m ); // condition 30 31 auto r = new ReadWriteMutex; // rwmutex 31 32 auto s = new Semaphore; // semaphore 32 33 }
