comparison druntime/src/compiler/ldc/lifetime.d @ 759:d3eb054172f9

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