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