Wiki Roadmap Timeline Tickets New Ticket Source Search Help / Guide About Trac Login

root/runtime/internal/lifetime.d

Revision 1506:76936858d1c6, 28.2 kB (checked in by Frits van Bommel <fvbommel wxs.nl>, 3 years ago)

Return void* from _d_allocclass so LLVM doesn't do weird things with it...
This allows -instcombine followed by -gvn to do devirtualization, so add
-gvn in strategic places in the default pass order.

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