comparison runtime/internal/lifetime.d @ 443:44f08170f4ef

Removed tango from the repository and instead added a runtime dir with the files needed to patch and build tango from svn. Reworked the LLVMDC specific pragmas.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Fri, 01 Aug 2008 00:32:06 +0200
parents
children f8c979770af3
comparison
equal deleted inserted replaced
442:76078c8ab5b9 443:44f08170f4ef
1 /**
2 * This module contains all functions related to an object's lifetime:
3 * allocation, resizing, deallocation, and finalization.
4 *
5 * Copyright: Copyright (C) 2004-2007 Digital Mars, www.digitalmars.com.
6 * All rights reserved.
7 * License:
8 * This software is provided 'as-is', without any express or implied
9 * warranty. In no event will the authors be held liable for any damages
10 * arising from the use of this software.
11 *
12 * Permission is granted to anyone to use this software for any purpose,
13 * including commercial applications, and to alter it and redistribute it
14 * freely, in both source and binary form, subject to the following
15 * restrictions:
16 *
17 * o The origin of this software must not be misrepresented; you must not
18 * claim that you wrote the original software. If you use this software
19 * in a product, an acknowledgment in the product documentation would be
20 * appreciated but is not required.
21 * o Altered source versions must be plainly marked as such, and must not
22 * be misrepresented as being the original software.
23 * o This notice may not be removed or altered from any source
24 * distribution.
25 * Authors: Walter Bright, Sean Kelly, Tomas Lindquist Olsen
26 */
27 module lifetime;
28
29 //debug=PRINTF;
30 //debug=PRINTF2;
31
32 private
33 {
34 import tango.stdc.stdlib;
35 import tango.stdc.string;
36 import tango.stdc.stdarg;
37 debug(PRINTF) import tango.stdc.stdio;
38 else debug(PRINTF2) import tango.stdc.stdio;
39 }
40
41
42 private
43 {
44 enum BlkAttr : uint
45 {
46 FINALIZE = 0b0000_0001,
47 NO_SCAN = 0b0000_0010,
48 NO_MOVE = 0b0000_0100,
49 ALL_BITS = 0b1111_1111
50 }
51
52 struct BlkInfo
53 {
54 void* base;
55 size_t size;
56 uint attr;
57 }
58
59 extern (C) uint gc_getAttr( void* p );
60 extern (C) uint gc_setAttr( void* p, uint a );
61 extern (C) uint gc_clrAttr( void* p, uint a );
62
63 extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
64 extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
65 extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
66 extern (C) void gc_free( void* p );
67
68 extern (C) void* gc_addrOf( void* p );
69 extern (C) size_t gc_sizeOf( void* p );
70 extern (C) BlkInfo gc_query( void* p );
71
72 extern (C) bool onCollectResource( Object o );
73 extern (C) void onFinalizeError( ClassInfo c, Exception e );
74 extern (C) void onOutOfMemoryError();
75
76 extern (C) void _d_monitordelete(Object h, bool det = true);
77
78 enum
79 {
80 PAGESIZE = 4096
81 }
82
83 alias bool function(Object) CollectHandler;
84 CollectHandler collectHandler = null;
85 }
86
87
88 /**
89 *
90 */
91 extern (C) Object _d_newclass(ClassInfo ci)
92 {
93 void* p;
94
95 debug(PRINTF2) printf("_d_newclass(ci = %p, %s)\n", ci, cast(char *)ci.name.ptr);
96 /+
97 if (ci.flags & 1) // if COM object
98 { /* COM objects are not garbage collected, they are reference counted
99 * using AddRef() and Release(). They get free'd by C's free()
100 * function called by Release() when Release()'s reference count goes
101 * to zero.
102 */
103 p = tango.stdc.stdlib.malloc(ci.init.length);
104 if (!p)
105 onOutOfMemoryError();
106 }
107 else
108 +/
109 {
110 p = gc_malloc(ci.init.length,
111 BlkAttr.FINALIZE | (ci.flags & 2 ? BlkAttr.NO_SCAN : 0));
112 debug(PRINTF2) printf(" p = %p\n", p);
113 }
114
115 debug(PRINTF2)
116 {
117 printf("p = %p\n", p);
118 printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init.ptr, ci.init.length);
119 printf("vptr = %p\n", *cast(void**) ci.init.ptr);
120 printf("vtbl[0] = %p\n", (*cast(void***) ci.init.ptr)[0]);
121 printf("vtbl[1] = %p\n", (*cast(void***) ci.init.ptr)[1]);
122 printf("init[0] = %p\n", (cast(uint**) ci.init.ptr)[0]);
123 printf("init[1] = %p\n", (cast(uint**) ci.init.ptr)[1]);
124 printf("init[2] = %p\n", (cast(uint**) ci.init.ptr)[2]);
125 printf("init[3] = %p\n", (cast(uint**) ci.init.ptr)[3]);
126 printf("init[4] = %p\n", (cast(uint**) ci.init.ptr)[4]);
127 }
128
129 // initialize it
130 // llvmdc does this inline
131 //(cast(byte*) p)[0 .. ci.init.length] = ci.init[];
132
133 debug(PRINTF) printf("initialization done\n");
134 return cast(Object) p;
135 }
136
137 /**
138 *
139 */
140 extern (C) void _d_delinterface(void* p)
141 {
142 if (p)
143 {
144 Interface* pi = **cast(Interface ***)p;
145 Object o = cast(Object)(p - pi.offset);
146
147 _d_delclass(o);
148 //*p = null;
149 }
150 }
151
152 // used for deletion
153 private extern (D) alias void function(Object) fp_t;
154
155
156 /**
157 *
158 */
159 extern (C) void _d_delclass(Object p)
160 {
161 if (p)
162 {
163 debug(PRINTF) printf("_d_delclass(%p)\n", p);
164
165 ClassInfo **pc = cast(ClassInfo **)p;
166 if (*pc)
167 {
168 ClassInfo c = **pc;
169
170 rt_finalize(cast(void*) p);
171
172 if (c.deallocator)
173 {
174 fp_t fp = cast(fp_t)c.deallocator;
175 (*fp)(p); // call deallocator
176 //*p = null;
177 return;
178 }
179 }
180 else
181 {
182 rt_finalize(cast(void*) p);
183 }
184 gc_free(cast(void*) p);
185 //*p = null;
186 }
187 }
188
189 /+
190
191 /**
192 *
193 */
194 struct Array
195 {
196 size_t length;
197 void* data;
198 }
199
200 +/
201
202 /**
203 * Allocate a new array of length elements.
204 * ti is the type of the resulting array, or pointer to element.
205 * (For when the array is initialized to 0)
206 */
207 extern (C) void* _d_newarrayT(TypeInfo ti, size_t length)
208 {
209 void* p;
210 auto size = ti.next.tsize(); // array element size
211
212 debug(PRINTF) printf("_d_newarrayT(length = %u, size = %d)\n", length, size);
213 if (length == 0 || size == 0)
214 return null;
215
216 version (D_InlineAsm_X86)
217 {
218 asm
219 {
220 mov EAX,size ;
221 mul EAX,length ;
222 mov size,EAX ;
223 jc Loverflow ;
224 }
225 }
226 else
227 size *= length;
228 p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
229 debug(PRINTF) printf(" p = %p\n", p);
230 memset(p, 0, size);
231 return p;
232
233 Loverflow:
234 onOutOfMemoryError();
235 return null;
236 }
237
238 /**
239 * For when the array has a non-zero initializer.
240 */
241 extern (C) void* _d_newarrayiT(TypeInfo ti, size_t length)
242 {
243 void* result;
244 auto size = ti.next.tsize(); // array element size
245
246 debug(PRINTF) printf("_d_newarrayiT(length = %d, size = %d)\n", length, size);
247
248 if (length == 0 || size == 0)
249 result = null;
250 else
251 {
252 auto initializer = ti.next.init();
253 auto isize = initializer.length;
254 auto q = initializer.ptr;
255 version (D_InlineAsm_X86)
256 {
257 asm
258 {
259 mov EAX,size ;
260 mul EAX,length ;
261 mov size,EAX ;
262 jc Loverflow ;
263 }
264 }
265 else
266 size *= length;
267 auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
268 debug(PRINTF) printf(" p = %p\n", p);
269 if (isize == 1)
270 memset(p, *cast(ubyte*)q, size);
271 else if (isize == int.sizeof)
272 {
273 int init = *cast(int*)q;
274 size /= int.sizeof;
275 for (size_t u = 0; u < size; u++)
276 {
277 (cast(int*)p)[u] = init;
278 }
279 }
280 else
281 {
282 for (size_t u = 0; u < size; u += isize)
283 {
284 memcpy(p + u, q, isize);
285 }
286 }
287 result = p;
288 }
289 return result;
290
291 Loverflow:
292 onOutOfMemoryError();
293 return null;
294 }
295
296 /**
297 *
298 */
299 extern (C) void* _d_newarraymT(TypeInfo ti, int ndims, size_t* dims)
300 {
301 void* result;
302
303 debug(PRINTF) printf("_d_newarraymT(ndims = %d)\n", ndims);
304 if (ndims == 0)
305 result = null;
306 else
307 {
308 static void[] foo(TypeInfo ti, size_t* pdim, int ndims)
309 {
310 size_t dim = *pdim;
311 void[] p;
312
313 debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims);
314 if (ndims == 1)
315 {
316 auto r = _d_newarrayT(ti, dim);
317 return r[0 .. dim];
318 }
319 else
320 {
321 p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
322 for (int i = 0; i < dim; i++)
323 {
324 (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
325 }
326 }
327 return p;
328 }
329
330 result = foo(ti, dims, ndims).ptr;
331 debug(PRINTF) printf("result = %p\n", result);
332
333 version (none)
334 {
335 for (int i = 0; i < ndims; i++)
336 {
337 printf("index %d: %d\n", i, *dims++);
338 }
339 }
340 }
341 return result;
342 }
343
344
345 /**
346 *
347 */
348 extern (C) void* _d_newarraymiT(TypeInfo ti, int ndims, size_t* dims)
349 {
350 void* result;
351
352 debug(PRINTF) printf("_d_newarraymiT(ndims = %d)\n", ndims);
353 if (ndims == 0)
354 result = null;
355 else
356 {
357 static void[] foo(TypeInfo ti, size_t* pdim, int ndims)
358 {
359 size_t dim = *pdim;
360 void[] p;
361
362 if (ndims == 1)
363 {
364 auto r = _d_newarrayiT(ti, dim);
365 p = r[0 .. dim];
366 }
367 else
368 {
369 p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
370 for (int i = 0; i < dim; i++)
371 {
372 (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
373 }
374 }
375 return p;
376 }
377
378 result = foo(ti, dims, ndims).ptr;
379 debug(PRINTF) printf("result = %p\n", result);
380
381 version (none)
382 {
383 for (int i = 0; i < ndims; i++)
384 {
385 printf("index %d: %d\n", i, *dims++);
386 printf("init = %d\n", *dims++);
387 }
388 }
389 }
390 return result;
391 }
392
393 /+
394
395 /**
396 *
397 */
398 void* _d_allocmemory(size_t nbytes)
399 {
400 return gc_malloc(nbytes);
401 }
402
403 +/
404
405 /**
406 * for allocating a single POD value
407 */
408 extern (C) void* _d_allocmemoryT(TypeInfo ti)
409 {
410 return gc_malloc(ti.tsize(), (ti.flags() & 1) ? BlkAttr.NO_SCAN : 0);
411 }
412
413 /**
414 *
415 */
416 extern (C) void _d_delarray(size_t plength, void* pdata)
417 {
418 // if (p)
419 // {
420 assert(!plength || pdata);
421
422 if (pdata)
423 gc_free(pdata);
424 // p.data = null;
425 // p.length = 0;
426 // }
427 }
428
429 /**
430 *
431 */
432 extern (C) void _d_delmemory(void* p)
433 {
434 if (p)
435 {
436 gc_free(p);
437 //*p = null;
438 }
439 }
440
441 /**
442 *
443 */
444 extern (C) void _d_callinterfacefinalizer(void *p)
445 {
446 if (p)
447 {
448 Interface *pi = **cast(Interface ***)p;
449 Object o = cast(Object)(p - pi.offset);
450 rt_finalize(cast(void*)o);
451 }
452 }
453
454 /**
455 *
456 */
457 extern (C) void _d_callfinalizer(void* p)
458 {
459 rt_finalize( p );
460 }
461
462
463 /**
464 *
465 */
466 extern (C) void rt_setCollectHandler(CollectHandler h)
467 {
468 collectHandler = h;
469 }
470
471 /**
472 *
473 */
474 extern (C) void rt_finalize(void* p, bool det = true)
475 {
476 debug(PRINTF) printf("rt_finalize(p = %p)\n", p);
477
478 if (p) // not necessary if called from gc
479 {
480 ClassInfo** pc = cast(ClassInfo**)p;
481
482 if (*pc)
483 {
484 ClassInfo c = **pc;
485
486 try
487 {
488 if (det || collectHandler is null || collectHandler(cast(Object)p))
489 {
490 do
491 {
492 if (c.destructor)
493 {
494 debug(PRINTF) printf("calling dtor of %.*s\n", c.name.length, c.name.ptr);
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 }
501 if ((cast(void**)p)[1]) // if monitor is not null
502 _d_monitordelete(cast(Object)p, det);
503 }
504 catch (Exception e)
505 {
506 onFinalizeError(**pc, e);
507 }
508 finally
509 {
510 *pc = null; // zero vptr
511 }
512 }
513 }
514 }
515
516 /**
517 * Resize dynamic arrays with 0 initializers.
518 */
519 extern (C) byte* _d_arraysetlengthT(TypeInfo ti, size_t newlength, size_t plength, byte* pdata)
520 in
521 {
522 assert(ti);
523 assert(!plength || pdata);
524 }
525 body
526 {
527 byte* newdata;
528 size_t sizeelem = ti.next.tsize();
529
530 debug(PRINTF)
531 {
532 printf("_d_arraysetlengthT(sizeelem = %d, newlength = %d)\n", sizeelem, newlength);
533 printf("\tp.data = %p, p.length = %d\n", pdata, plength);
534 }
535
536 if (newlength)
537 {
538 version (D_InlineAsm_X86)
539 {
540 size_t newsize = void;
541
542 asm
543 {
544 mov EAX, newlength;
545 mul EAX, sizeelem;
546 mov newsize, EAX;
547 jc Loverflow;
548 }
549 }
550 else
551 {
552 size_t newsize = sizeelem * newlength;
553
554 if (newsize / newlength != sizeelem)
555 goto Loverflow;
556 }
557
558 debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
559
560 if (pdata)
561 {
562 newdata = pdata;
563 if (newlength > plength)
564 {
565 size_t size = plength * sizeelem;
566 auto info = gc_query(pdata);
567
568 if (info.size <= newsize || info.base != pdata)
569 {
570 if (info.size >= PAGESIZE && info.base == pdata)
571 { // Try to extend in-place
572 auto u = gc_extend(pdata, (newsize + 1) - info.size, (newsize + 1) - info.size);
573 if (u)
574 {
575 goto L1;
576 }
577 }
578 newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
579 newdata[0 .. size] = pdata[0 .. size];
580 }
581 L1:
582 newdata[size .. newsize] = 0;
583 }
584 }
585 else
586 {
587 newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
588 }
589 }
590 else
591 {
592 newdata = pdata;
593 }
594
595 return newdata;
596
597 Loverflow:
598 onOutOfMemoryError();
599 return null;
600 }
601
602
603 /**
604 * Resize arrays for non-zero initializers.
605 * p pointer to array lvalue to be updated
606 * newlength new .length property of array
607 * sizeelem size of each element of array
608 * initsize size of initializer
609 * ... initializer
610 */
611 extern (C) byte* _d_arraysetlengthiT(TypeInfo ti, size_t newlength, size_t plength, byte* pdata)
612 in
613 {
614 assert(!plength || pdata);
615 }
616 body
617 {
618 byte* newdata;
619 TypeInfo tinext = ti.next;
620 size_t sizeelem = tinext.tsize();
621 void[] initializer = tinext.init();
622 size_t initsize = initializer.length;
623
624 assert(sizeelem);
625 assert(initsize);
626 assert(initsize <= sizeelem);
627 assert((sizeelem / initsize) * initsize == sizeelem);
628
629 debug(PRINTF)
630 {
631 printf("_d_arraysetlengthiT(sizeelem = %d, newlength = %d, initsize = %d)\n", sizeelem, newlength, initsize);
632 printf("\tp.data = %p, p.length = %d\n", pdata, plength);
633 }
634
635 if (newlength)
636 {
637 version (D_InlineAsm_X86)
638 {
639 size_t newsize = void;
640
641 asm
642 {
643 mov EAX,newlength ;
644 mul EAX,sizeelem ;
645 mov newsize,EAX ;
646 jc Loverflow ;
647 }
648 }
649 else
650 {
651 size_t newsize = sizeelem * newlength;
652
653 if (newsize / newlength != sizeelem)
654 goto Loverflow;
655 }
656 debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
657
658 size_t size = plength * sizeelem;
659
660 if (pdata)
661 {
662 newdata = pdata;
663 if (newlength > plength)
664 {
665 auto info = gc_query(pdata);
666
667 if (info.size <= newsize || info.base != pdata)
668 {
669 if (info.size >= PAGESIZE && info.base == pdata)
670 { // Try to extend in-place
671 auto u = gc_extend(pdata, (newsize + 1) - info.size, (newsize + 1) - info.size);
672 if (u)
673 {
674 goto L1;
675 }
676 }
677 newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
678 newdata[0 .. size] = pdata[0 .. size];
679 L1: ;
680 }
681 }
682 }
683 else
684 {
685 newdata = cast(byte *)gc_malloc(newsize + 1, !(tinext.flags() & 1) ? BlkAttr.NO_SCAN : 0);
686 }
687
688 auto q = initializer.ptr; // pointer to initializer
689
690 if (newsize > size)
691 {
692 if (initsize == 1)
693 {
694 debug(PRINTF) printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q);
695 newdata[size .. newsize] = *(cast(byte*)q);
696 }
697 else
698 {
699 for (size_t u = size; u < newsize; u += initsize)
700 {
701 memcpy(newdata + u, q, initsize);
702 }
703 }
704 }
705 }
706 else
707 {
708 newdata = pdata;
709 }
710
711 return newdata;
712
713 Loverflow:
714 onOutOfMemoryError();
715 return null;
716 }
717
718 /+
719
720 /**
721 * Append y[] to array x[].
722 * size is size of each array element.
723 */
724 extern (C) long _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)
725 {
726 auto sizeelem = ti.next.tsize(); // array element size
727 auto info = gc_query(px.data);
728 auto length = px.length;
729 auto newlength = length + y.length;
730 auto newsize = newlength * sizeelem;
731
732 if (info.size < newsize || info.base != px.data)
733 { byte* newdata;
734
735 if (info.size >= PAGESIZE && info.base == px.data)
736 { // Try to extend in-place
737 auto u = gc_extend(px.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
738 if (u)
739 {
740 goto L1;
741 }
742 }
743 newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr);
744 memcpy(newdata, px.data, length * sizeelem);
745 px.data = newdata;
746 }
747 L1:
748 px.length = newlength;
749 memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem);
750 return *cast(long*)px;
751 }
752
753
754 /**
755 *
756 */
757 size_t newCapacity(size_t newlength, size_t size)
758 {
759 version(none)
760 {
761 size_t newcap = newlength * size;
762 }
763 else
764 {
765 /*
766 * Better version by Dave Fladebo:
767 * This uses an inverse logorithmic algorithm to pre-allocate a bit more
768 * space for larger arrays.
769 * - Arrays smaller than PAGESIZE bytes are left as-is, so for the most
770 * common cases, memory allocation is 1 to 1. The small overhead added
771 * doesn't affect small array perf. (it's virtually the same as
772 * current).
773 * - Larger arrays have some space pre-allocated.
774 * - As the arrays grow, the relative pre-allocated space shrinks.
775 * - The logorithmic algorithm allocates relatively more space for
776 * mid-size arrays, making it very fast for medium arrays (for
777 * mid-to-large arrays, this turns out to be quite a bit faster than the
778 * equivalent realloc() code in C, on Linux at least. Small arrays are
779 * just as fast as GCC).
780 * - Perhaps most importantly, overall memory usage and stress on the GC
781 * is decreased significantly for demanding environments.
782 */
783 size_t newcap = newlength * size;
784 size_t newext = 0;
785
786 if (newcap > PAGESIZE)
787 {
788 //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0)));
789
790 // redo above line using only integer math
791
792 static int log2plus1(size_t c)
793 { int i;
794
795 if (c == 0)
796 i = -1;
797 else
798 for (i = 1; c >>= 1; i++)
799 {
800 }
801 return i;
802 }
803
804 /* The following setting for mult sets how much bigger
805 * the new size will be over what is actually needed.
806 * 100 means the same size, more means proportionally more.
807 * More means faster but more memory consumption.
808 */
809 //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap));
810 long mult = 100 + (1000L * size) / log2plus1(newcap);
811
812 // testing shows 1.02 for large arrays is about the point of diminishing return
813 if (mult < 102)
814 mult = 102;
815 newext = cast(size_t)((newcap * mult) / 100);
816 newext -= newext % size;
817 debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/100.0,newext / cast(double)size);
818 }
819 newcap = newext > newcap ? newext : newcap;
820 debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size);
821 }
822 return newcap;
823 }
824
825
826 /**
827 *
828 */
829 extern (C) byte[] _d_arrayappendcT(TypeInfo ti, inout byte[] x, ...)
830 {
831 auto sizeelem = ti.next.tsize(); // array element size
832 auto info = gc_query(x.ptr);
833 auto length = x.length;
834 auto newlength = length + 1;
835 auto newsize = newlength * sizeelem;
836
837 assert(info.size == 0 || length * sizeelem <= info.size);
838
839 debug(PRINTF) printf("_d_arrayappendcT(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size);
840
841 if (info.size <= newsize || info.base != x.ptr)
842 { byte* newdata;
843
844 if (info.size >= PAGESIZE && info.base == x.ptr)
845 { // Try to extend in-place
846 auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size);
847 if (u)
848 {
849 goto L1;
850 }
851 }
852 debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size);
853 auto newcap = newCapacity(newlength, sizeelem);
854 assert(newcap >= newlength * sizeelem);
855 newdata = cast(byte *)gc_malloc(newcap + 1, info.attr);
856 memcpy(newdata, x.ptr, length * sizeelem);
857 (cast(void**)(&x))[1] = newdata;
858 }
859 L1:
860 byte *argp = cast(byte *)(&ti + 2);
861
862 *cast(size_t *)&x = newlength;
863 x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
864 assert((cast(size_t)x.ptr & 15) == 0);
865 assert(gc_sizeOf(x.ptr) > x.length * sizeelem);
866 return x;
867 }
868
869
870 /**
871 *
872 */
873 extern (C) byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y)
874 out (result)
875 {
876 auto sizeelem = ti.next.tsize(); // array element size
877 debug(PRINTF) 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);
878 assert(result.length == x.length + y.length);
879 for (size_t i = 0; i < x.length * sizeelem; i++)
880 assert((cast(byte*)result)[i] == (cast(byte*)x)[i]);
881 for (size_t i = 0; i < y.length * sizeelem; i++)
882 assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]);
883
884 size_t cap = gc_sizeOf(result.ptr);
885 assert(!cap || cap > result.length * sizeelem);
886 }
887 body
888 {
889 version (none)
890 {
891 /* Cannot use this optimization because:
892 * char[] a, b;
893 * char c = 'a';
894 * b = a ~ c;
895 * c = 'b';
896 * will change the contents of b.
897 */
898 if (!y.length)
899 return x;
900 if (!x.length)
901 return y;
902 }
903
904 debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr);
905 auto sizeelem = ti.next.tsize(); // array element size
906 debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem);
907 size_t xlen = x.length * sizeelem;
908 size_t ylen = y.length * sizeelem;
909 size_t len = xlen + ylen;
910
911 if (!len)
912 return null;
913
914 byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
915 memcpy(p, x.ptr, xlen);
916 memcpy(p + xlen, y.ptr, ylen);
917 p[len] = 0;
918 return p[0 .. x.length + y.length];
919 }
920
921
922 /**
923 *
924 */
925 extern (C) byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
926 { void* a;
927 size_t length;
928 byte[]* p;
929 uint i;
930 byte[] b;
931 auto size = ti.next.tsize(); // array element size
932
933 p = cast(byte[]*)(&n + 1);
934
935 for (i = 0; i < n; i++)
936 {
937 b = *p++;
938 length += b.length;
939 }
940 if (!length)
941 return null;
942
943 a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
944 p = cast(byte[]*)(&n + 1);
945
946 uint j = 0;
947 for (i = 0; i < n; i++)
948 {
949 b = *p++;
950 if (b.length)
951 {
952 memcpy(a + j, b.ptr, b.length * size);
953 j += b.length * size;
954 }
955 }
956
957 byte[] result;
958 *cast(int *)&result = length; // jam length
959 (cast(void **)&result)[1] = a; // jam ptr
960 return result;
961 }
962
963
964 /**
965 *
966 */
967 extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...)
968 {
969 auto sizeelem = ti.next.tsize(); // array element size
970 void* result;
971
972 debug(PRINTF) printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length);
973 if (length == 0 || sizeelem == 0)
974 result = null;
975 else
976 {
977 result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
978
979 va_list q;
980 va_start!(size_t)(q, length);
981
982 size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1);
983
984 if (stacksize == sizeelem)
985 {
986 memcpy(result, q, length * sizeelem);
987 }
988 else
989 {
990 for (size_t i = 0; i < length; i++)
991 {
992 memcpy(result + i * sizeelem, q, sizeelem);
993 q += stacksize;
994 }
995 }
996
997 va_end(q);
998 }
999 return result;
1000 }
1001
1002 +/
1003
1004
1005 /**
1006 * Support for array.dup property.
1007 */
1008 struct Array2
1009 {
1010 size_t length;
1011 void* ptr;
1012 }
1013
1014
1015 /**
1016 *
1017 */
1018 extern (C) Array2 _adDupT(TypeInfo ti, Array2 a)
1019 out (result)
1020 {
1021 auto sizeelem = ti.next.tsize(); // array element size
1022 assert(memcmp(result.ptr, a.ptr, a.length * sizeelem) == 0);
1023 }
1024 body
1025 {
1026 Array2 r;
1027
1028 if (a.length)
1029 {
1030 auto sizeelem = ti.next.tsize(); // array element size
1031 auto size = a.length * sizeelem;
1032 r.ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
1033 r.length = a.length;
1034 memcpy(r.ptr, a.ptr, size);
1035 }
1036 return r;
1037 }
1038
1039
1040 unittest
1041 {
1042 int[] a;
1043 int[] b;
1044 int i;
1045
1046 a = new int[3];
1047 a[0] = 1; a[1] = 2; a[2] = 3;
1048 b = a.dup;
1049 assert(b.length == 3);
1050 for (i = 0; i < 3; i++)
1051 assert(b[i] == i + 1);
1052 }