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