Mercurial > projects > ldc
comparison druntime/src/gc/stub/gc.d @ 1458:e0b2d67cfe7c
Added druntime (this should be removed once it works).
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Tue, 02 Jun 2009 17:43:06 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1456:7b218ec1044f | 1458:e0b2d67cfe7c |
---|---|
1 /** | |
2 * This module contains a minimal garbage collector implementation according to | |
3 * published requirements. This library is mostly intended to serve as an | |
4 * example, but it is usable in applications which do not rely on a garbage | |
5 * collector to clean up memory (ie. when dynamic array resizing is not used, | |
6 * and all memory allocated with 'new' is freed deterministically with | |
7 * 'delete'). | |
8 * | |
9 * Please note that block attribute data must be tracked, or at a minimum, the | |
10 * FINALIZE bit must be tracked for any allocated memory block because calling | |
11 * rt_finalize on a non-object block can result in an access violation. In the | |
12 * allocator below, this tracking is done via a leading uint bitmask. A real | |
13 * allocator may do better to store this data separately, similar to the basic | |
14 * GC. | |
15 * | |
16 * Copyright: Copyright Sean Kelly 2005 - 2009. | |
17 * License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>. | |
18 * Authors: Sean Kelly | |
19 * | |
20 * Copyright Sean Kelly 2005 - 2009. | |
21 * Distributed under the Boost Software License, Version 1.0. | |
22 * (See accompanying file LICENSE_1_0.txt or copy at | |
23 * http://www.boost.org/LICENSE_1_0.txt) | |
24 */ | |
25 module gc.gc; | |
26 | |
27 private | |
28 { | |
29 import core.stdc.stdlib; | |
30 | |
31 enum BlkAttr : uint | |
32 { | |
33 FINALIZE = 0b0000_0001, | |
34 NO_SCAN = 0b0000_0010, | |
35 NO_MOVE = 0b0000_0100, | |
36 ALL_BITS = 0b1111_1111 | |
37 } | |
38 | |
39 struct BlkInfo | |
40 { | |
41 void* base; | |
42 size_t size; | |
43 uint attr; | |
44 } | |
45 | |
46 extern (C) void thread_init(); | |
47 extern (C) void onOutOfMemoryError(); | |
48 | |
49 struct Proxy | |
50 { | |
51 extern (C) void function() gc_enable; | |
52 extern (C) void function() gc_disable; | |
53 extern (C) void function() gc_collect; | |
54 extern (C) void function() gc_minimize; | |
55 | |
56 extern (C) uint function(void*) gc_getAttr; | |
57 extern (C) uint function(void*, uint) gc_setAttr; | |
58 extern (C) uint function(void*, uint) gc_clrAttr; | |
59 | |
60 extern (C) void* function(size_t, uint) gc_malloc; | |
61 extern (C) void* function(size_t, uint) gc_calloc; | |
62 extern (C) void* function(void*, size_t, uint ba) gc_realloc; | |
63 extern (C) size_t function(void*, size_t, size_t) gc_extend; | |
64 extern (C) size_t function(size_t) gc_reserve; | |
65 extern (C) void function(void*) gc_free; | |
66 | |
67 extern (C) void* function(void*) gc_addrOf; | |
68 extern (C) size_t function(void*) gc_sizeOf; | |
69 | |
70 extern (C) BlkInfo function(void*) gc_query; | |
71 | |
72 extern (C) void function(void*) gc_addRoot; | |
73 extern (C) void function(void*, size_t) gc_addRange; | |
74 | |
75 extern (C) void function(void*) gc_removeRoot; | |
76 extern (C) void function(void*) gc_removeRange; | |
77 } | |
78 | |
79 __gshared Proxy pthis; | |
80 __gshared Proxy* proxy; | |
81 | |
82 void initProxy() | |
83 { | |
84 pthis.gc_enable = &gc_enable; | |
85 pthis.gc_disable = &gc_disable; | |
86 pthis.gc_collect = &gc_collect; | |
87 pthis.gc_minimize = &gc_minimize; | |
88 | |
89 pthis.gc_getAttr = &gc_getAttr; | |
90 pthis.gc_setAttr = &gc_setAttr; | |
91 pthis.gc_clrAttr = &gc_clrAttr; | |
92 | |
93 pthis.gc_malloc = &gc_malloc; | |
94 pthis.gc_calloc = &gc_calloc; | |
95 pthis.gc_realloc = &gc_realloc; | |
96 pthis.gc_extend = &gc_extend; | |
97 pthis.gc_reserve = &gc_reserve; | |
98 pthis.gc_free = &gc_free; | |
99 | |
100 pthis.gc_addrOf = &gc_addrOf; | |
101 pthis.gc_sizeOf = &gc_sizeOf; | |
102 | |
103 pthis.gc_query = &gc_query; | |
104 | |
105 pthis.gc_addRoot = &gc_addRoot; | |
106 pthis.gc_addRange = &gc_addRange; | |
107 | |
108 pthis.gc_removeRoot = &gc_removeRoot; | |
109 pthis.gc_removeRange = &gc_removeRange; | |
110 } | |
111 | |
112 __gshared void** roots = null; | |
113 __gshared size_t nroots = 0; | |
114 | |
115 struct Range | |
116 { | |
117 void* pos; | |
118 size_t len; | |
119 } | |
120 | |
121 __gshared Range* ranges = null; | |
122 __gshared size_t nranges = 0; | |
123 } | |
124 | |
125 extern (C) void gc_init() | |
126 { | |
127 // NOTE: The GC must initialize the thread library before its first | |
128 // collection, and always before returning from gc_init(). | |
129 thread_init(); | |
130 initProxy(); | |
131 } | |
132 | |
133 extern (C) void gc_term() | |
134 { | |
135 free( roots ); | |
136 free( ranges ); | |
137 } | |
138 | |
139 extern (C) void gc_enable() | |
140 { | |
141 if( proxy is null ) | |
142 return; | |
143 return proxy.gc_enable(); | |
144 } | |
145 | |
146 extern (C) void gc_disable() | |
147 { | |
148 if( proxy is null ) | |
149 return; | |
150 return proxy.gc_disable(); | |
151 } | |
152 | |
153 extern (C) void gc_collect() | |
154 { | |
155 if( proxy is null ) | |
156 return; | |
157 return proxy.gc_collect(); | |
158 } | |
159 | |
160 extern (C) void gc_minimize() | |
161 { | |
162 if( proxy is null ) | |
163 return; | |
164 return proxy.gc_minimize(); | |
165 } | |
166 | |
167 extern (C) uint gc_getAttr( void* p ) | |
168 { | |
169 if( proxy is null ) | |
170 return 0; | |
171 return proxy.gc_getAttr( p ); | |
172 } | |
173 | |
174 extern (C) uint gc_setAttr( void* p, uint a ) | |
175 { | |
176 if( proxy is null ) | |
177 return 0; | |
178 return proxy.gc_setAttr( p, a ); | |
179 } | |
180 | |
181 extern (C) uint gc_clrAttr( void* p, uint a ) | |
182 { | |
183 if( proxy is null ) | |
184 return 0; | |
185 return proxy.gc_clrAttr( p, a ); | |
186 } | |
187 | |
188 extern (C) void* gc_malloc( size_t sz, uint ba = 0 ) | |
189 { | |
190 if( proxy is null ) | |
191 { | |
192 void* p = malloc( sz ); | |
193 | |
194 if( sz && p is null ) | |
195 onOutOfMemoryError(); | |
196 return p; | |
197 } | |
198 return proxy.gc_malloc( sz, ba ); | |
199 } | |
200 | |
201 extern (C) void* gc_calloc( size_t sz, uint ba = 0 ) | |
202 { | |
203 if( proxy is null ) | |
204 { | |
205 void* p = calloc( 1, sz ); | |
206 | |
207 if( sz && p is null ) | |
208 onOutOfMemoryError(); | |
209 return p; | |
210 } | |
211 return proxy.gc_calloc( sz, ba ); | |
212 } | |
213 | |
214 extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 ) | |
215 { | |
216 if( proxy is null ) | |
217 { | |
218 p = realloc( p, sz ); | |
219 | |
220 if( sz && p is null ) | |
221 onOutOfMemoryError(); | |
222 return p; | |
223 } | |
224 return proxy.gc_realloc( p, sz, ba ); | |
225 } | |
226 | |
227 extern (C) size_t gc_extend( void* p, size_t mx, size_t sz ) | |
228 { | |
229 if( proxy is null ) | |
230 return 0; | |
231 return proxy.gc_extend( p, mx, sz ); | |
232 } | |
233 | |
234 extern (C) size_t gc_reserve( size_t sz ) | |
235 { | |
236 if( proxy is null ) | |
237 return 0; | |
238 return proxy.gc_reserve( sz ); | |
239 } | |
240 | |
241 extern (C) void gc_free( void* p ) | |
242 { | |
243 if( proxy is null ) | |
244 return free( p ); | |
245 return proxy.gc_free( p ); | |
246 } | |
247 | |
248 extern (C) void* gc_addrOf( void* p ) | |
249 { | |
250 if( proxy is null ) | |
251 return null; | |
252 return proxy.gc_addrOf( p ); | |
253 } | |
254 | |
255 extern (C) size_t gc_sizeOf( void* p ) | |
256 { | |
257 if( proxy is null ) | |
258 return 0; | |
259 return proxy.gc_sizeOf( p ); | |
260 } | |
261 | |
262 extern (C) BlkInfo gc_query( void* p ) | |
263 { | |
264 if( proxy is null ) | |
265 return BlkInfo.init; | |
266 return proxy.gc_query( p ); | |
267 } | |
268 | |
269 extern (C) void gc_addRoot( void* p ) | |
270 { | |
271 if( proxy is null ) | |
272 { | |
273 void** r = cast(void**) realloc( roots, | |
274 (nroots+1) * roots[0].sizeof ); | |
275 if( r is null ) | |
276 onOutOfMemoryError(); | |
277 r[nroots++] = p; | |
278 roots = r; | |
279 | |
280 } | |
281 return proxy.gc_addRoot( p ); | |
282 } | |
283 | |
284 extern (C) void gc_addRange( void* p, size_t sz ) | |
285 { | |
286 if( proxy is null ) | |
287 { | |
288 Range* r = cast(Range*) realloc( ranges, | |
289 (nranges+1) * ranges[0].sizeof ); | |
290 if( r is null ) | |
291 onOutOfMemoryError(); | |
292 r[nranges].pos = p; | |
293 r[nranges].len = sz; | |
294 ranges = r; | |
295 ++nranges; | |
296 } | |
297 return proxy.gc_addRange( p, sz ); | |
298 } | |
299 | |
300 extern (C) void gc_removeRoot( void *p ) | |
301 { | |
302 if( proxy is null ) | |
303 { | |
304 for( size_t i = 0; i < nroots; ++i ) | |
305 { | |
306 if( roots[i] is p ) | |
307 { | |
308 roots[i] = roots[--nroots]; | |
309 return; | |
310 } | |
311 } | |
312 assert( false ); | |
313 } | |
314 return proxy.gc_removeRoot( p ); | |
315 } | |
316 | |
317 extern (C) void gc_removeRange( void *p ) | |
318 { | |
319 if( proxy is null ) | |
320 { | |
321 for( size_t i = 0; i < nranges; ++i ) | |
322 { | |
323 if( ranges[i].pos is p ) | |
324 { | |
325 ranges[i] = ranges[--nranges]; | |
326 return; | |
327 } | |
328 } | |
329 assert( false ); | |
330 } | |
331 return proxy.gc_removeRange( p ); | |
332 } | |
333 | |
334 extern (C) Proxy* gc_getProxy() | |
335 { | |
336 return &pthis; | |
337 } | |
338 | |
339 export extern (C) void gc_setProxy( Proxy* p ) | |
340 { | |
341 if( proxy !is null ) | |
342 { | |
343 // TODO: Decide if this is an error condition. | |
344 } | |
345 proxy = p; | |
346 foreach( r; roots[0 .. nroots] ) | |
347 proxy.gc_addRoot( r ); | |
348 foreach( r; ranges[0 .. nranges] ) | |
349 proxy.gc_addRange( r.pos, r.len ); | |
350 } | |
351 | |
352 export extern (C) void gc_clrProxy() | |
353 { | |
354 foreach( r; ranges[0 .. nranges] ) | |
355 proxy.gc_removeRange( r.pos ); | |
356 foreach( r; roots[0 .. nroots] ) | |
357 proxy.gc_removeRoot( r ); | |
358 proxy = null; | |
359 } |