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; }