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