Mercurial > projects > ldc
annotate tango/lib/compiler/llvmdc/lifetime.d @ 305:2b72433d5c8c trunk
[svn r326] Fixed a bunch of issues with printf's that MinGW32 did not support.
Fixed problems with label collisions when using labels inside inline asm. LabelStatement is now easily reached given its
Identifier, which should be useful elsewhere too.
Enabled inline asm for building the lib/compiler/llvmdc runtime code, fixing branches out of asm makes this possible.
author | lindquist |
---|---|
date | Fri, 27 Jun 2008 22:04:35 +0200 |
parents | a3b7c19c866c |
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 } |