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