root/trunk/src/rt/lifetime.d

Revision 220, 30.7 kB (checked in by walter, 5 years ago)

inout to ref

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