Mercurial > projects > ldc
comparison lphobos/gc/gc.d @ 473:373489eeaf90
Applied downs' lphobos update
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Mon, 04 Aug 2008 19:28:49 +0200 |
parents | 5825d48b27d1 |
children | 88e23f8c2354 |
comparison
equal
deleted
inserted
replaced
472:15c804b6ce77 | 473:373489eeaf90 |
---|---|
1 /** | 1 /** |
2 * Part of the D programming language runtime library. | 2 * Part of the D programming language runtime library. |
3 */ | 3 */ |
4 | 4 |
5 /* | 5 /* |
6 * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com | 6 * Copyright (C) 2004-2008 by Digital Mars, www.digitalmars.com |
7 * Written by Walter Bright | 7 * Written by Walter Bright |
8 * | 8 * |
9 * This software is provided 'as-is', without any express or implied | 9 * This software is provided 'as-is', without any express or implied |
10 * warranty. In no event will the authors be held liable for any damages | 10 * warranty. In no event will the authors be held liable for any damages |
11 * arising from the use of this software. | 11 * arising from the use of this software. |
22 * be misrepresented as being the original software. | 22 * be misrepresented as being the original software. |
23 * o This notice may not be removed or altered from any source | 23 * o This notice may not be removed or altered from any source |
24 * distribution. | 24 * distribution. |
25 */ | 25 */ |
26 | 26 |
27 /* NOTE: This file has been patched from the original DMD distribution to | |
28 work with the GDC compiler. | |
29 | |
30 Modified by David Friedman, February 2007 | |
31 */ | |
32 | |
27 | 33 |
28 // Storage allocation | 34 // Storage allocation |
29 | 35 |
30 module std.gc; | 36 module std.gc; |
31 | 37 |
118 } | 124 } |
119 | 125 |
120 extern (C) | 126 extern (C) |
121 { | 127 { |
122 | 128 |
123 void _d_monitorrelease(Object h); | 129 void _d_monitorexit(Object h); |
124 | 130 |
125 | 131 |
126 void gc_init() | 132 void gc_init() |
127 { | 133 { |
128 version (GCCLASS) | 134 version (GCCLASS) |
146 { | 152 { |
147 _gc.fullCollectNoStack(); | 153 _gc.fullCollectNoStack(); |
148 _gc.Dtor(); | 154 _gc.Dtor(); |
149 } | 155 } |
150 | 156 |
151 } | 157 Object _d_newclass(ClassInfo ci) |
158 { | |
159 void *p; | |
160 | |
161 debug(PRINTF) printf("_d_newclass(ci = %p, %s)\n", ci, cast(char *)ci.name); | |
162 if (ci.flags & 1) // if COM object | |
163 { | |
164 p = std.c.stdlib.malloc(ci.init.length); | |
165 if (!p) | |
166 _d_OutOfMemory(); | |
167 debug(PRINTF) printf(" COM object p = %p\n", p); | |
168 } | |
169 else | |
170 { | |
171 p = _gc.malloc(ci.init.length); | |
172 debug(PRINTF) printf(" p = %p\n", p); | |
173 _gc.setFinalizer(p, &new_finalizer); | |
174 if (ci.flags & 2) | |
175 _gc.hasNoPointers(p); | |
176 } | |
177 | |
178 debug (PRINTF) | |
179 { | |
180 printf("p = %p\n", p); | |
181 printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length); | |
182 printf("vptr = %p\n", *cast(void **)ci.init); | |
183 printf("vtbl[0] = %p\n", (*cast(void ***)ci.init)[0]); | |
184 printf("vtbl[1] = %p\n", (*cast(void ***)ci.init)[1]); | |
185 printf("init[0] = %x\n", (cast(uint *)ci.init)[0]); | |
186 printf("init[1] = %x\n", (cast(uint *)ci.init)[1]); | |
187 printf("init[2] = %x\n", (cast(uint *)ci.init)[2]); | |
188 printf("init[3] = %x\n", (cast(uint *)ci.init)[3]); | |
189 printf("init[4] = %x\n", (cast(uint *)ci.init)[4]); | |
190 } | |
191 | |
192 | |
193 // Initialize it | |
194 (cast(byte*)p)[0 .. ci.init.length] = ci.init[]; | |
195 | |
196 //printf("initialization done\n"); | |
197 return cast(Object)p; | |
198 } | |
199 | |
200 extern (D) alias void (*fp_t)(Object); // generic function pointer | |
201 | |
202 void _d_delinterface(void** p) | |
203 { | |
204 if (*p) | |
205 { | |
206 Interface *pi = **cast(Interface ***)*p; | |
207 Object o; | |
208 | |
209 o = cast(Object)(*p - pi.offset); | |
210 _d_delclass(&o); | |
211 *p = null; | |
212 } | |
213 } | |
214 | |
215 void _d_delclass(Object *p) | |
216 { | |
217 if (*p) | |
218 { | |
219 debug (PRINTF) printf("_d_delclass(%p)\n", *p); | |
220 version(0) | |
221 { | |
222 ClassInfo **pc = cast(ClassInfo **)*p; | |
223 if (*pc) | |
224 { | |
225 ClassInfo c = **pc; | |
226 | |
227 if (c.deallocator) | |
228 { | |
229 _d_callfinalizer(cast(void *)(*p)); | |
230 fp_t fp = cast(fp_t)c.deallocator; | |
231 (*fp)(*p); // call deallocator | |
232 *p = null; | |
233 return; | |
234 } | |
235 } | |
236 } | |
237 _gc.free(cast(void*)(*p)); | |
238 *p = null; | |
239 } | |
240 } | |
241 | |
242 /****************************************** | |
243 * Allocate a new array of length elements. | |
244 * ti is the type of the resulting array, or pointer to element. | |
245 */ | |
246 | |
247 /* For when the array is initialized to 0 */ | |
248 void* _d_newarrayT(TypeInfo ti, size_t length) | |
249 { | |
250 void* result; | |
251 auto size = ti.next.tsize(); // array element size | |
252 | |
253 debug(PRINTF) printf("_d_newarrayT(length = x%x, size = %d)\n", length, size); | |
254 if (length && size) | |
255 { | |
256 /*version (D_InlineAsm_X86) | |
257 { | |
258 asm | |
259 { | |
260 mov EAX,size ; | |
261 mul EAX,length ; | |
262 mov size,EAX ; | |
263 jc Loverflow ; | |
264 } | |
265 } | |
266 else*/ | |
267 size *= length; | |
268 result = cast(byte*) _gc.malloc(size + 1); | |
269 if (!(ti.next.flags() & 1)) | |
270 _gc.hasNoPointers(result); | |
271 memset(result, 0, size); | |
272 } | |
273 return result; | |
274 | |
275 Loverflow: | |
276 _d_OutOfMemory(); | |
277 } | |
278 | |
279 /* For when the array has a non-zero initializer. | |
280 */ | |
281 void* _d_newarrayiT(TypeInfo ti, size_t length) | |
282 { | |
283 void* result; | |
284 auto size = ti.next.tsize(); // array element size | |
285 | |
286 debug(PRINTF) | |
287 printf("_d_newarrayiT(length = %d, size = %d)\n", length, size); | |
288 if (length == 0 || size == 0) | |
289 { } | |
290 else | |
291 { | |
292 auto initializer = ti.next.init(); | |
293 auto isize = initializer.length; | |
294 auto q = initializer.ptr; | |
295 /*version (D_InlineAsm_X86) | |
296 { | |
297 asm | |
298 { | |
299 mov EAX,size ; | |
300 mul EAX,length ; | |
301 mov size,EAX ; | |
302 jc Loverflow ; | |
303 } | |
304 } | |
305 else*/ | |
306 size *= length; | |
307 auto p = _gc.malloc(size + 1); | |
308 debug(PRINTF) printf(" p = %p\n", p); | |
309 if (!(ti.next.flags() & 1)) | |
310 _gc.hasNoPointers(p); | |
311 if (isize == 1) | |
312 memset(p, *cast(ubyte*)q, size); | |
313 else if (isize == int.sizeof) | |
314 { | |
315 int init = *cast(int*)q; | |
316 size /= int.sizeof; | |
317 for (size_t u = 0; u < size; u++) | |
318 { | |
319 (cast(int*)p)[u] = init; | |
320 } | |
321 } | |
322 else | |
323 { | |
324 for (size_t u = 0; u < size; u += isize) | |
325 { | |
326 memcpy(p + u, q, isize); | |
327 } | |
328 } | |
329 result = cast(byte*) p | |
330 ; | |
331 } | |
332 return result; | |
333 | |
334 Loverflow: | |
335 _d_OutOfMemory(); | |
336 } | |
337 | |
338 void[] _d_newarraymTp(TypeInfo ti, int ndims, size_t* pdim) | |
339 { | |
340 void[] result = void; | |
341 | |
342 //debug(PRINTF) | |
343 //printf("_d_newarraymT(ndims = %d)\n", ndims); | |
344 if (ndims == 0) | |
345 result = null; | |
346 else | |
347 { | |
348 | |
349 void[] foo(TypeInfo ti, size_t* pdim, int ndims) | |
350 { | |
351 size_t dim = *pdim; | |
352 void[] p; | |
353 | |
354 //printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims); | |
355 if (ndims == 1) | |
356 { | |
357 auto r = _d_newarrayT(ti, dim); | |
358 p = *cast(void[]*)(&r); | |
359 } | |
360 else | |
361 { | |
362 p = _gc.malloc(dim * (void[]).sizeof + 1)[0 .. dim]; | |
363 for (int i = 0; i < dim; i++) | |
364 { | |
365 (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1); | |
366 } | |
367 } | |
368 return p; | |
369 } | |
370 | |
371 result = foo(ti, pdim, ndims); | |
372 //printf("result = %llx\n", result); | |
373 | |
374 version (none) | |
375 { | |
376 for (int i = 0; i < ndims; i++) | |
377 { | |
378 printf("index %d: %d\n", i, pdim[i]); | |
379 } | |
380 } | |
381 } | |
382 return result; | |
383 } | |
384 | |
385 void[] _d_newarraymiTp(TypeInfo ti, int ndims, size_t* pdim) | |
386 { | |
387 void[] result = void; | |
388 | |
389 //debug(PRINTF) | |
390 //printf("_d_newarraymi(size = %d, ndims = %d)\n", size, ndims); | |
391 if (ndims == 0) | |
392 result = null; | |
393 else | |
394 { | |
395 | |
396 void[] foo(TypeInfo ti, size_t* pdim, int ndims) | |
397 { | |
398 size_t dim = *pdim; | |
399 void[] p; | |
400 | |
401 if (ndims == 1) | |
402 { | |
403 auto r = _d_newarrayiT(ti, dim); | |
404 p = *cast(void[]*)(&r); | |
405 } | |
406 else | |
407 { | |
408 p = _gc.malloc(dim * (void[]).sizeof + 1)[0 .. dim]; | |
409 for (int i = 0; i < dim; i++) | |
410 { | |
411 (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1); | |
412 } | |
413 } | |
414 return p; | |
415 } | |
416 | |
417 result = foo(ti, pdim, ndims); | |
418 //printf("result = %llx\n", result); | |
419 | |
420 version (none) | |
421 { | |
422 for (int i = 0; i < ndims; i++) | |
423 { | |
424 printf("index %d: %d\n", i, pdim[i]); | |
425 printf("init = %d\n", *cast(int*)pinit); | |
426 } | |
427 } | |
428 } | |
429 return result; | |
430 } | |
431 | |
432 struct Array | |
433 { | |
434 size_t length; | |
435 byte *data; | |
436 }; | |
437 | |
438 // Perhaps we should get a a size argument like _d_new(), so we | |
439 // can zero out the array? | |
440 | |
441 void _d_delarray(size_t plength, void* pdata) | |
442 { | |
443 assert(!plength || pdata); | |
444 if (pdata) _gc.free(pdata); | |
445 } | |
446 | |
447 | |
448 void _d_delmemory(void* *p) | |
449 { | |
450 if (*p) | |
451 { | |
452 _gc.free(*p); | |
453 *p = null; | |
454 } | |
455 } | |
456 | |
457 | |
458 } | |
459 | |
460 void new_finalizer(void *p, bool dummy) | |
461 { | |
462 //printf("new_finalizer(p = %p)\n", p); | |
463 _d_callfinalizer(p); | |
464 } | |
465 | |
466 extern (C) | |
467 void _d_callinterfacefinalizer(void *p) | |
468 { | |
469 //printf("_d_callinterfacefinalizer(p = %p)\n", p); | |
470 if (p) | |
471 { | |
472 Interface *pi = **cast(Interface ***)p; | |
473 Object o = cast(Object)(p - pi.offset); | |
474 _d_callfinalizer(cast(void*)o); | |
475 } | |
476 } | |
477 | |
478 extern (C) | |
479 void _d_callfinalizer(void *p) | |
480 { | |
481 //printf("_d_callfinalizer(p = %p)\n", p); | |
482 if (p) // not necessary if called from gc | |
483 { | |
484 ClassInfo **pc = cast(ClassInfo **)p; | |
485 if (*pc) | |
486 { | |
487 ClassInfo c = **pc; | |
488 | |
489 try | |
490 { | |
491 do | |
492 { | |
493 if (c.destructor) | |
494 { | |
495 fp_t fp = cast(fp_t)c.destructor; | |
496 (*fp)(cast(Object)p); // call destructor | |
497 } | |
498 c = c.base; | |
499 } while (c); | |
500 if ((cast(void**)p)[1]) // if monitor is not null | |
501 _d_monitorexit(cast(Object)p); | |
502 } | |
503 finally | |
504 { | |
505 *pc = null; // zero vptr | |
506 } | |
507 } | |
508 } | |
509 } | |
510 | |
511 /+ ------------------------------------------------ +/ | |
512 | |
513 | |
514 /****************************** | |
515 * Resize dynamic arrays with 0 initializers. | |
516 */ | |
517 | |
518 extern (C) | |
519 byte* _d_arraysetlengthT(TypeInfo ti, size_t newlength, size_t plength, byte* pdata) | |
520 in | |
521 { | |
522 assert(ti); | |
523 } | |
524 body | |
525 { | |
526 byte* newdata; | |
527 size_t sizeelem = ti.next.tsize(); | |
528 | |
529 debug(PRINTF) | |
530 { | |
531 printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength); | |
532 if (p) | |
533 printf("\tpdata = %p, plength = %d\n", pdata, plength); | |
534 } | |
535 | |
536 if (newlength) | |
537 { | |
538 version (GNU) | |
539 { | |
540 // required to output the label; | |
541 static char x = 0; | |
542 if (x) | |
543 goto Loverflow; | |
544 } | |
545 | |
546 version (D_InlineAsm_X86) | |
547 { | |
548 size_t newsize = void; | |
549 | |
550 asm | |
551 { | |
552 mov EAX,newlength ; | |
553 mul EAX,sizeelem ; | |
554 mov newsize,EAX ; | |
555 jc Loverflow ; | |
556 } | |
557 } | |
558 else | |
559 { | |
560 size_t newsize = sizeelem * newlength; | |
561 | |
562 if (newsize / newlength != sizeelem) | |
563 goto Loverflow; | |
564 } | |
565 //printf("newsize = %x, newlength = %x\n", newsize, newlength); | |
566 | |
567 if (pdata) | |
568 { | |
569 newdata = pdata; | |
570 if (newlength > plength) | |
571 { | |
572 size_t size = plength * sizeelem; | |
573 size_t cap = _gc.capacity(pdata); | |
574 | |
575 if (cap <= newsize) | |
576 { | |
577 if (cap >= 4096) | |
578 { // Try to extend in-place | |
579 auto u = _gc.extend(pdata, (newsize + 1) - cap, (newsize + 1) - cap); | |
580 if (u) | |
581 { | |
582 goto L1; | |
583 } | |
584 } | |
585 newdata = cast(byte *)_gc.malloc(newsize + 1); | |
586 newdata[0 .. size] = pdata[0 .. size]; | |
587 if (!(ti.next.flags() & 1)) | |
588 _gc.hasNoPointers(newdata); | |
589 } | |
590 L1: | |
591 newdata[size .. newsize] = 0; | |
592 } | |
593 } | |
594 else | |
595 { | |
596 newdata = cast(byte *)_gc.calloc(newsize + 1, 1); | |
597 if (!(ti.next.flags() & 1)) | |
598 _gc.hasNoPointers(newdata); | |
599 } | |
600 } | |
601 else | |
602 { | |
603 newdata = pdata; | |
604 } | |
605 | |
606 pdata = newdata; | |
607 plength = newlength; | |
608 return newdata; | |
609 | |
610 Loverflow: | |
611 _d_OutOfMemory(); | |
612 } | |
613 | |
614 /** | |
615 * Resize arrays for non-zero initializers. | |
616 * p pointer to array lvalue to be updated | |
617 * newlength new .length property of array | |
618 * sizeelem size of each element of array | |
619 * initsize size of initializer | |
620 * ... initializer | |
621 */ | |
622 extern (C) | |
623 byte* _d_arraysetlengthiT(TypeInfo ti, size_t newlength, size_t plength, byte* pdata) | |
624 in | |
625 { | |
626 assert(!plength || pdata); | |
627 } | |
628 body | |
629 { | |
630 byte* newdata; | |
631 size_t sizeelem = ti.next.tsize(); | |
632 void[] initializer = ti.next.init(); | |
633 size_t initsize = initializer.length; | |
634 | |
635 assert(sizeelem); | |
636 assert(initsize); | |
637 assert(initsize <= sizeelem); | |
638 assert((sizeelem / initsize) * initsize == sizeelem); | |
639 | |
640 debug(PRINTF) | |
641 { | |
642 printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d)\n", p, sizeelem, newlength, initsize); | |
643 if (p) | |
644 printf("\tpdata = %p, plength = %d\n", pdata, plength); | |
645 } | |
646 | |
647 if (newlength) | |
648 { | |
649 version (GNU) | |
650 { | |
651 // required to output the label; | |
652 static char x = 0; | |
653 if (x) | |
654 goto Loverflow; | |
655 } | |
656 | |
657 version (D_InlineAsm_X86) | |
658 { | |
659 size_t newsize = void; | |
660 | |
661 asm | |
662 { | |
663 mov EAX,newlength ; | |
664 mul EAX,sizeelem ; | |
665 mov newsize,EAX ; | |
666 jc Loverflow ; | |
667 } | |
668 } | |
669 else | |
670 { | |
671 size_t newsize = sizeelem * newlength; | |
672 | |
673 if (newsize / newlength != sizeelem) | |
674 goto Loverflow; | |
675 } | |
676 //printf("newsize = %x, newlength = %x\n", newsize, newlength); | |
677 | |
678 size_t size = plength * sizeelem; | |
679 if (pdata) | |
680 { | |
681 newdata = pdata; | |
682 if (newlength > plength) | |
683 { | |
684 size_t cap = _gc.capacity(pdata); | |
685 | |
686 if (cap <= newsize) | |
687 { | |
688 if (cap >= 4096) | |
689 { // Try to extend in-place | |
690 auto u = _gc.extend(pdata, (newsize + 1) - cap, (newsize + 1) - cap); | |
691 if (u) | |
692 { | |
693 goto L1; | |
694 } | |
695 } | |
696 newdata = cast(byte *)_gc.malloc(newsize + 1); | |
697 newdata[0 .. size] = pdata[0 .. size]; | |
698 L1: ; | |
699 } | |
700 } | |
701 } | |
702 else | |
703 { | |
704 newdata = cast(byte *)_gc.malloc(newsize + 1); | |
705 if (!(ti.next.flags() & 1)) | |
706 _gc.hasNoPointers(newdata); | |
707 } | |
708 | |
709 auto q = initializer.ptr; // pointer to initializer | |
710 | |
711 if (newsize > size) | |
712 { | |
713 if (initsize == 1) | |
714 { | |
715 //printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q); | |
716 newdata[size .. newsize] = *(cast(byte*)q); | |
717 } | |
718 else | |
719 { | |
720 for (size_t u = size; u < newsize; u += initsize) | |
721 { | |
722 memcpy(newdata + u, q, initsize); | |
723 } | |
724 } | |
725 } | |
726 } | |
727 else | |
728 { | |
729 newdata = pdata; | |
730 } | |
731 | |
732 pdata = newdata; | |
733 plength = newlength; | |
734 return newdata; | |
735 | |
736 Loverflow: | |
737 _d_OutOfMemory(); | |
738 } | |
739 | |
740 /**************************************** | |
741 * Append y[] to array x[]. | |
742 * size is size of each array element. | |
743 */ | |
744 | |
745 extern (C) | |
746 Array _d_arrayappendT(TypeInfo ti, Array *px, byte[] y) | |
747 { | |
748 auto sizeelem = ti.next.tsize(); // array element size | |
749 auto cap = _gc.capacity(px.data); | |
750 auto length = px.length; | |
751 auto newlength = length + y.length; | |
752 auto newsize = newlength * sizeelem; | |
753 if (newsize > cap) | |
754 { byte* newdata; | |
755 | |
756 if (cap >= 4096) | |
757 { // Try to extend in-place | |
758 auto u = _gc.extend(px.data, (newsize + 1) - cap, (newsize + 1) - cap); | |
759 if (u) | |
760 { | |
761 goto L1; | |
762 } | |
763 } | |
764 | |
765 newdata = cast(byte *)_gc.malloc(newCapacity(newlength, sizeelem) + 1); | |
766 if (!(ti.next.flags() & 1)) | |
767 _gc.hasNoPointers(newdata); | |
768 memcpy(newdata, px.data, length * sizeelem); | |
769 px.data = newdata; | |
770 } | |
771 L1: | |
772 px.length = newlength; | |
773 memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem); | |
774 return *px; | |
775 } | |
776 | |
777 size_t newCapacity(size_t newlength, size_t size) | |
778 { | |
779 version(none) | |
780 { | |
781 size_t newcap = newlength * size; | |
782 } | |
783 else | |
784 { | |
785 /* | |
786 * Better version by Dave Fladebo: | |
787 * This uses an inverse logorithmic algorithm to pre-allocate a bit more | |
788 * space for larger arrays. | |
789 * - Arrays smaller than 4096 bytes are left as-is, so for the most | |
790 * common cases, memory allocation is 1 to 1. The small overhead added | |
791 * doesn't effect small array perf. (it's virtually the same as | |
792 * current). | |
793 * - Larger arrays have some space pre-allocated. | |
794 * - As the arrays grow, the relative pre-allocated space shrinks. | |
795 * - The logorithmic algorithm allocates relatively more space for | |
796 * mid-size arrays, making it very fast for medium arrays (for | |
797 * mid-to-large arrays, this turns out to be quite a bit faster than the | |
798 * equivalent realloc() code in C, on Linux at least. Small arrays are | |
799 * just as fast as GCC). | |
800 * - Perhaps most importantly, overall memory usage and stress on the GC | |
801 * is decreased significantly for demanding environments. | |
802 */ | |
803 size_t newcap = newlength * size; | |
804 size_t newext = 0; | |
805 | |
806 if (newcap > 4096) | |
807 { | |
808 //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0))); | |
809 | |
810 // Redo above line using only integer math | |
811 | |
812 static int log2plus1(size_t c) | |
813 { int i; | |
814 | |
815 if (c == 0) | |
816 i = -1; | |
817 else | |
818 for (i = 1; c >>= 1; i++) | |
819 { } | |
820 return i; | |
821 } | |
822 | |
823 /* The following setting for mult sets how much bigger | |
824 * the new size will be over what is actually needed. | |
825 * 100 means the same size, more means proportionally more. | |
826 * More means faster but more memory consumption. | |
827 */ | |
828 //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap)); | |
829 long mult = 100 + (1000L * size) / log2plus1(newcap); | |
830 | |
831 // testing shows 1.02 for large arrays is about the point of diminishing return | |
832 if (mult < 102) | |
833 mult = 102; | |
834 newext = cast(size_t)((newcap * mult) / 100); | |
835 newext -= newext % size; | |
836 //printf("mult: %2.2f, mult2: %2.2f, alloc: %2.2f\n",mult/100.0,mult2,newext / cast(double)size); | |
837 } | |
838 newcap = newext > newcap ? newext : newcap; | |
839 //printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size); | |
840 } | |
841 return newcap; | |
842 } | |
843 | |
844 extern (C) | |
845 byte[] _d_arrayappendcTp(TypeInfo ti, inout byte[] x, byte *argp) | |
846 { | |
847 auto sizeelem = ti.next.tsize(); // array element size | |
848 auto cap = _gc.capacity(x.ptr); | |
849 auto length = x.length; | |
850 auto newlength = length + 1; | |
851 auto newsize = newlength * sizeelem; | |
852 | |
853 assert(cap == 0 || length * sizeelem <= cap); | |
854 | |
855 //printf("_d_arrayappendc(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, cap); | |
856 | |
857 if (newsize >= cap) | |
858 { byte* newdata; | |
859 | |
860 if (cap >= 4096) | |
861 { // Try to extend in-place | |
862 auto u = _gc.extend(x.ptr, (newsize + 1) - cap, (newsize + 1) - cap); | |
863 if (u) | |
864 { | |
865 goto L1; | |
866 } | |
867 } | |
868 | |
869 //printf("_d_arrayappendc(sizeelem = %d, newlength = %d, cap = %d)\n", sizeelem, newlength, cap); | |
870 cap = newCapacity(newlength, sizeelem); | |
871 assert(cap >= newlength * sizeelem); | |
872 newdata = cast(byte *)_gc.malloc(cap + 1); | |
873 if (!(ti.next.flags() & 1)) | |
874 _gc.hasNoPointers(newdata); | |
875 memcpy(newdata, x.ptr, length * sizeelem); | |
876 (cast(void **)(&x))[1] = newdata; | |
877 } | |
878 L1: | |
879 | |
880 *cast(size_t *)&x = newlength; | |
881 x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem]; | |
882 assert((cast(size_t)x.ptr & 15) == 0); | |
883 assert(_gc.capacity(x.ptr) >= x.length * sizeelem); | |
884 return x; | |
885 } | |
886 | |
887 extern (C) | |
888 byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y) | |
889 out (result) | |
890 { | |
891 auto sizeelem = ti.next.tsize(); // array element size | |
892 //printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr); | |
893 assert(result.length == x.length + y.length); | |
894 for (size_t i = 0; i < x.length * sizeelem; i++) | |
895 assert((cast(byte*)result)[i] == (cast(byte*)x)[i]); | |
896 for (size_t i = 0; i < y.length * sizeelem; i++) | |
897 assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]); | |
898 | |
899 size_t cap = _gc.capacity(result.ptr); | |
900 assert(!cap || cap > result.length * sizeelem); | |
901 } | |
902 body | |
903 { | |
904 version (none) | |
905 { | |
906 /* Cannot use this optimization because: | |
907 * char[] a, b; | |
908 * char c = 'a'; | |
909 * b = a ~ c; | |
910 * c = 'b'; | |
911 * will change the contents of b. | |
912 */ | |
913 if (!y.length) | |
914 return x; | |
915 if (!x.length) | |
916 return y; | |
917 } | |
918 | |
919 //printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr); | |
920 auto sizeelem = ti.next.tsize(); // array element size | |
921 //printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem); | |
922 size_t xlen = x.length * sizeelem; | |
923 size_t ylen = y.length * sizeelem; | |
924 size_t len = xlen + ylen; | |
925 if (!len) | |
926 return null; | |
927 | |
928 byte* p = cast(byte*)_gc.malloc(len + 1); | |
929 if (!(ti.next.flags() & 1)) | |
930 _gc.hasNoPointers(p); | |
931 memcpy(p, x.ptr, xlen); | |
932 memcpy(p + xlen, y.ptr, ylen); | |
933 p[len] = 0; | |
934 | |
935 return p[0 .. x.length + y.length]; | |
936 } | |
937 | |
938 | |
939 extern (C) | |
940 byte[] _d_arraycatnT(TypeInfo ti, uint n, ...) | |
941 { void* a; | |
942 size_t length; | |
943 byte[]* p; | |
944 uint i; | |
945 byte[] b; | |
946 va_list va; | |
947 auto sizeelem = ti.next.tsize(); // array element size | |
948 | |
949 va_start!(typeof(n))(va, n); | |
950 | |
951 for (i = 0; i < n; i++) | |
952 { | |
953 b = va_arg!(typeof(b))(va); | |
954 length += b.length; | |
955 } | |
956 if (!length) | |
957 return null; | |
958 | |
959 a = _gc.malloc(length * sizeelem); | |
960 if (!(ti.next.flags() & 1)) | |
961 _gc.hasNoPointers(a); | |
962 va_start!(typeof(n))(va, n); | |
963 | |
964 uint j = 0; | |
965 for (i = 0; i < n; i++) | |
966 { | |
967 b = va_arg!(typeof(b))(va); | |
968 if (b.length) | |
969 { | |
970 memcpy(a + j, b.ptr, b.length * sizeelem); | |
971 j += b.length * sizeelem; | |
972 } | |
973 } | |
974 | |
975 return (cast(byte*)a)[0..length]; | |
976 } | |
977 | |
978 version (GNU) { } else | |
979 extern (C) | |
980 void* _d_arrayliteralT(TypeInfo ti, size_t length, ...) | |
981 { | |
982 auto sizeelem = ti.next.tsize(); // array element size | |
983 void* result; | |
984 | |
985 //printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length); | |
986 if (length == 0 || sizeelem == 0) | |
987 result = null; | |
988 else | |
989 { | |
990 result = _gc.malloc(length * sizeelem); | |
991 if (!(ti.next.flags() & 1)) | |
992 { | |
993 _gc.hasNoPointers(result); | |
994 } | |
995 | |
996 va_list q; | |
997 va_start!(size_t)(q, length); | |
998 | |
999 size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1); | |
1000 | |
1001 if (stacksize == sizeelem) | |
1002 { | |
1003 memcpy(result, q, length * sizeelem); | |
1004 } | |
1005 else | |
1006 { | |
1007 for (size_t i = 0; i < length; i++) | |
1008 { | |
1009 memcpy(result + i * sizeelem, q, sizeelem); | |
1010 q += stacksize; | |
1011 } | |
1012 } | |
1013 | |
1014 va_end(q); | |
1015 } | |
1016 return result; | |
1017 } | |
1018 | |
1019 /********************************** | |
1020 * Support for array.dup property. | |
1021 */ | |
1022 | |
1023 /*struct Array2 | |
1024 { | |
1025 size_t length; | |
1026 void* ptr; | |
1027 }*/ | |
1028 | |
1029 extern(C) void* _d_allocmemoryT(size_t foo) { return malloc(foo).ptr; } |