comparison druntime/src/compiler/dmd/lifetime.d @ 1458:e0b2d67cfe7c

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