Mercurial > emacs
comparison gc/gcc_support.c @ 51488:5de98dce4bd1
*** empty log message ***
author | Dave Love <fx@gnu.org> |
---|---|
date | Thu, 05 Jun 2003 17:49:22 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
51487:01d68b199093 | 51488:5de98dce4bd1 |
---|---|
1 /*************************************************************************** | |
2 | |
3 Interface between g++ and Boehm GC | |
4 | |
5 Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. | |
6 | |
7 THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED | |
8 OR IMPLIED. ANY USE IS AT YOUR OWN RISK. | |
9 | |
10 Permission is hereby granted to copy this code for any purpose, | |
11 provided the above notices are retained on all copies. | |
12 | |
13 Last modified on Sun Jul 16 23:21:14 PDT 1995 by ellis | |
14 | |
15 This module provides runtime support for implementing the | |
16 Ellis/Detlefs GC proposal, "Safe, Efficient Garbage Collection for | |
17 C++", within g++, using its -fgc-keyword extension. It defines | |
18 versions of __builtin_new, __builtin_new_gc, __builtin_vec_new, | |
19 __builtin_vec_new_gc, __builtin_delete, and __builtin_vec_delete that | |
20 invoke the Bohem GC. It also implements the WeakPointer.h interface. | |
21 | |
22 This module assumes the following configuration options of the Boehm GC: | |
23 | |
24 -DALL_INTERIOR_POINTERS | |
25 -DDONT_ADD_BYTE_AT_END | |
26 | |
27 This module adds its own required padding to the end of objects to | |
28 support C/C++ "one-past-the-object" pointer semantics. | |
29 | |
30 ****************************************************************************/ | |
31 | |
32 #include <stddef.h> | |
33 #include "gc.h" | |
34 | |
35 #if defined(__STDC__) | |
36 # define PROTO( args ) args | |
37 #else | |
38 # define PROTO( args ) () | |
39 # endif | |
40 | |
41 #define BITSPERBYTE 8 | |
42 /* What's the portable way to do this? */ | |
43 | |
44 | |
45 typedef void (*vfp) PROTO(( void )); | |
46 extern vfp __new_handler; | |
47 extern void __default_new_handler PROTO(( void )); | |
48 | |
49 | |
50 /* A destructor_proc is the compiler generated procedure representing a | |
51 C++ destructor. The "flag" argument is a hidden argument following some | |
52 compiler convention. */ | |
53 | |
54 typedef (*destructor_proc) PROTO(( void* this, int flag )); | |
55 | |
56 | |
57 /*************************************************************************** | |
58 | |
59 A BI_header is the header the compiler adds to the front of | |
60 new-allocated arrays of objects with destructors. The header is | |
61 padded out to a double, because that's what the compiler does to | |
62 ensure proper alignment of array elements on some architectures. | |
63 | |
64 int NUM_ARRAY_ELEMENTS (void* o) | |
65 returns the number of array elements for array object o. | |
66 | |
67 char* FIRST_ELEMENT_P (void* o) | |
68 returns the address of the first element of array object o. | |
69 | |
70 ***************************************************************************/ | |
71 | |
72 typedef struct BI_header { | |
73 int nelts; | |
74 char padding [sizeof( double ) - sizeof( int )]; | |
75 /* Better way to do this? */ | |
76 } BI_header; | |
77 | |
78 #define NUM_ARRAY_ELEMENTS( o ) \ | |
79 (((BI_header*) o)->nelts) | |
80 | |
81 #define FIRST_ELEMENT_P( o ) \ | |
82 ((char*) o + sizeof( BI_header )) | |
83 | |
84 | |
85 /*************************************************************************** | |
86 | |
87 The __builtin_new routines add a descriptor word to the end of each | |
88 object. The descriptor serves two purposes. | |
89 | |
90 First, the descriptor acts as padding, implementing C/C++ pointer | |
91 semantics. C and C++ allow a valid array pointer to be incremented | |
92 one past the end of an object. The extra padding ensures that the | |
93 collector will recognize that such a pointer points to the object and | |
94 not the next object in memory. | |
95 | |
96 Second, the descriptor stores three extra pieces of information, | |
97 whether an object has a registered finalizer (destructor), whether it | |
98 may have any weak pointers referencing it, and for collectible arrays, | |
99 the element size of the array. The element size is required for the | |
100 array's finalizer to iterate through the elements of the array. (An | |
101 alternative design would have the compiler generate a finalizer | |
102 procedure for each different array type. But given the overhead of | |
103 finalization, there isn't any efficiency to be gained by that.) | |
104 | |
105 The descriptor must be added to non-collectible as well as collectible | |
106 objects, since the Ellis/Detlefs proposal allows "pointer to gc T" to | |
107 be assigned to a "pointer to T", which could then be deleted. Thus, | |
108 __builtin_delete must determine at runtime whether an object is | |
109 collectible, whether it has weak pointers referencing it, and whether | |
110 it may have a finalizer that needs unregistering. Though | |
111 GC_REGISTER_FINALIZER doesn't care if you ask it to unregister a | |
112 finalizer for an object that doesn't have one, it is a non-trivial | |
113 procedure that does a hash look-up, etc. The descriptor trades a | |
114 little extra space for a significant increase in time on the fast path | |
115 through delete. (A similar argument applies to | |
116 GC_UNREGISTER_DISAPPEARING_LINK). | |
117 | |
118 For non-array types, the space for the descriptor could be shrunk to a | |
119 single byte for storing the "has finalizer" flag. But this would save | |
120 space only on arrays of char (whose size is not a multiple of the word | |
121 size) and structs whose largest member is less than a word in size | |
122 (very infrequent). And it would require that programmers actually | |
123 remember to call "delete[]" instead of "delete" (which they should, | |
124 but there are probably lots of buggy programs out there). For the | |
125 moment, the space savings seems not worthwhile, especially considering | |
126 that the Boehm GC is already quite space competitive with other | |
127 malloc's. | |
128 | |
129 | |
130 Given a pointer o to the base of an object: | |
131 | |
132 Descriptor* DESCRIPTOR (void* o) | |
133 returns a pointer to the descriptor for o. | |
134 | |
135 The implementation of descriptors relies on the fact that the GC | |
136 implementation allocates objects in units of the machine's natural | |
137 word size (e.g. 32 bits on a SPARC, 64 bits on an Alpha). | |
138 | |
139 **************************************************************************/ | |
140 | |
141 typedef struct Descriptor { | |
142 unsigned has_weak_pointers: 1; | |
143 unsigned has_finalizer: 1; | |
144 unsigned element_size: BITSPERBYTE * sizeof( unsigned ) - 2; | |
145 } Descriptor; | |
146 | |
147 #define DESCRIPTOR( o ) \ | |
148 ((Descriptor*) ((char*)(o) + GC_size( o ) - sizeof( Descriptor ))) | |
149 | |
150 | |
151 /************************************************************************** | |
152 | |
153 Implementations of global operator new() and operator delete() | |
154 | |
155 ***************************************************************************/ | |
156 | |
157 | |
158 void* __builtin_new( size ) | |
159 size_t size; | |
160 /* | |
161 For non-gc non-array types, the compiler generates calls to | |
162 __builtin_new, which allocates non-collected storage via | |
163 GC_MALLOC_UNCOLLECTABLE. This ensures that the non-collected | |
164 storage will be part of the collector's root set, required by the | |
165 Ellis/Detlefs semantics. */ | |
166 { | |
167 vfp handler = __new_handler ? __new_handler : __default_new_handler; | |
168 | |
169 while (1) { | |
170 void* o = GC_MALLOC_UNCOLLECTABLE( size + sizeof( Descriptor ) ); | |
171 if (o != 0) return o; | |
172 (*handler) ();}} | |
173 | |
174 | |
175 void* __builtin_vec_new( size ) | |
176 size_t size; | |
177 /* | |
178 For non-gc array types, the compiler generates calls to | |
179 __builtin_vec_new. */ | |
180 { | |
181 return __builtin_new( size );} | |
182 | |
183 | |
184 void* __builtin_new_gc( size ) | |
185 size_t size; | |
186 /* | |
187 For gc non-array types, the compiler generates calls to | |
188 __builtin_new_gc, which allocates collected storage via | |
189 GC_MALLOC. */ | |
190 { | |
191 vfp handler = __new_handler ? __new_handler : __default_new_handler; | |
192 | |
193 while (1) { | |
194 void* o = GC_MALLOC( size + sizeof( Descriptor ) ); | |
195 if (o != 0) return o; | |
196 (*handler) ();}} | |
197 | |
198 | |
199 void* __builtin_new_gc_a( size ) | |
200 size_t size; | |
201 /* | |
202 For non-pointer-containing gc non-array types, the compiler | |
203 generates calls to __builtin_new_gc_a, which allocates collected | |
204 storage via GC_MALLOC_ATOMIC. */ | |
205 { | |
206 vfp handler = __new_handler ? __new_handler : __default_new_handler; | |
207 | |
208 while (1) { | |
209 void* o = GC_MALLOC_ATOMIC( size + sizeof( Descriptor ) ); | |
210 if (o != 0) return o; | |
211 (*handler) ();}} | |
212 | |
213 | |
214 void* __builtin_vec_new_gc( size ) | |
215 size_t size; | |
216 /* | |
217 For gc array types, the compiler generates calls to | |
218 __builtin_vec_new_gc. */ | |
219 { | |
220 return __builtin_new_gc( size );} | |
221 | |
222 | |
223 void* __builtin_vec_new_gc_a( size ) | |
224 size_t size; | |
225 /* | |
226 For non-pointer-containing gc array types, the compiler generates | |
227 calls to __builtin_vec_new_gc_a. */ | |
228 { | |
229 return __builtin_new_gc_a( size );} | |
230 | |
231 | |
232 static void call_destructor( o, data ) | |
233 void* o; | |
234 void* data; | |
235 /* | |
236 call_destructor is the GC finalizer proc registered for non-array | |
237 gc objects with destructors. Its client data is the destructor | |
238 proc, which it calls with the magic integer 2, a special flag | |
239 obeying the compiler convention for destructors. */ | |
240 { | |
241 ((destructor_proc) data)( o, 2 );} | |
242 | |
243 | |
244 void* __builtin_new_gc_dtor( o, d ) | |
245 void* o; | |
246 destructor_proc d; | |
247 /* | |
248 The compiler generates a call to __builtin_new_gc_dtor to register | |
249 the destructor "d" of a non-array gc object "o" as a GC finalizer. | |
250 The destructor is registered via | |
251 GC_REGISTER_FINALIZER_IGNORE_SELF, which causes the collector to | |
252 ignore pointers from the object to itself when determining when | |
253 the object can be finalized. This is necessary due to the self | |
254 pointers used in the internal representation of multiply-inherited | |
255 objects. */ | |
256 { | |
257 Descriptor* desc = DESCRIPTOR( o ); | |
258 | |
259 GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_destructor, d, 0, 0 ); | |
260 desc->has_finalizer = 1;} | |
261 | |
262 | |
263 static void call_array_destructor( o, data ) | |
264 void* o; | |
265 void* data; | |
266 /* | |
267 call_array_destructor is the GC finalizer proc registered for gc | |
268 array objects whose elements have destructors. Its client data is | |
269 the destructor proc. It iterates through the elements of the | |
270 array in reverse order, calling the destructor on each. */ | |
271 { | |
272 int num = NUM_ARRAY_ELEMENTS( o ); | |
273 Descriptor* desc = DESCRIPTOR( o ); | |
274 size_t size = desc->element_size; | |
275 char* first_p = FIRST_ELEMENT_P( o ); | |
276 char* p = first_p + (num - 1) * size; | |
277 | |
278 if (num > 0) { | |
279 while (1) { | |
280 ((destructor_proc) data)( p, 2 ); | |
281 if (p == first_p) break; | |
282 p -= size;}}} | |
283 | |
284 | |
285 void* __builtin_vec_new_gc_dtor( first_elem, d, element_size ) | |
286 void* first_elem; | |
287 destructor_proc d; | |
288 size_t element_size; | |
289 /* | |
290 The compiler generates a call to __builtin_vec_new_gc_dtor to | |
291 register the destructor "d" of a gc array object as a GC | |
292 finalizer. "first_elem" points to the first element of the array, | |
293 *not* the beginning of the object (this makes the generated call | |
294 to this function smaller). The elements of the array are of size | |
295 "element_size". The destructor is registered as in | |
296 _builtin_new_gc_dtor. */ | |
297 { | |
298 void* o = (char*) first_elem - sizeof( BI_header ); | |
299 Descriptor* desc = DESCRIPTOR( o ); | |
300 | |
301 GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_array_destructor, d, 0, 0 ); | |
302 desc->element_size = element_size; | |
303 desc->has_finalizer = 1;} | |
304 | |
305 | |
306 void __builtin_delete( o ) | |
307 void* o; | |
308 /* | |
309 The compiler generates calls to __builtin_delete for operator | |
310 delete(). The GC currently requires that any registered | |
311 finalizers be unregistered before explicitly freeing an object. | |
312 If the object has any weak pointers referencing it, we can't | |
313 actually free it now. */ | |
314 { | |
315 if (o != 0) { | |
316 Descriptor* desc = DESCRIPTOR( o ); | |
317 if (desc->has_finalizer) GC_REGISTER_FINALIZER( o, 0, 0, 0, 0 ); | |
318 if (! desc->has_weak_pointers) GC_FREE( o );}} | |
319 | |
320 | |
321 void __builtin_vec_delete( o ) | |
322 void* o; | |
323 /* | |
324 The compiler generates calls to __builitn_vec_delete for operator | |
325 delete[](). */ | |
326 { | |
327 __builtin_delete( o );} | |
328 | |
329 | |
330 /************************************************************************** | |
331 | |
332 Implementations of the template class WeakPointer from WeakPointer.h | |
333 | |
334 ***************************************************************************/ | |
335 | |
336 typedef struct WeakPointer { | |
337 void* pointer; | |
338 } WeakPointer; | |
339 | |
340 | |
341 void* _WeakPointer_New( t ) | |
342 void* t; | |
343 { | |
344 if (t == 0) { | |
345 return 0;} | |
346 else { | |
347 void* base = GC_base( t ); | |
348 WeakPointer* wp = | |
349 (WeakPointer*) GC_MALLOC_ATOMIC( sizeof( WeakPointer ) ); | |
350 Descriptor* desc = DESCRIPTOR( base ); | |
351 | |
352 wp->pointer = t; | |
353 desc->has_weak_pointers = 1; | |
354 GC_general_register_disappearing_link( &wp->pointer, base ); | |
355 return wp;}} | |
356 | |
357 | |
358 static void* PointerWithLock( wp ) | |
359 WeakPointer* wp; | |
360 { | |
361 if (wp == 0 || wp->pointer == 0) { | |
362 return 0;} | |
363 else { | |
364 return (void*) wp->pointer;}} | |
365 | |
366 | |
367 void* _WeakPointer_Pointer( wp ) | |
368 WeakPointer* wp; | |
369 { | |
370 return (void*) GC_call_with_alloc_lock( PointerWithLock, wp );} | |
371 | |
372 | |
373 typedef struct EqualClosure { | |
374 WeakPointer* wp1; | |
375 WeakPointer* wp2; | |
376 } EqualClosure; | |
377 | |
378 | |
379 static void* EqualWithLock( ec ) | |
380 EqualClosure* ec; | |
381 { | |
382 if (ec->wp1 == 0 || ec->wp2 == 0) { | |
383 return (void*) (ec->wp1 == ec->wp2);} | |
384 else { | |
385 return (void*) (ec->wp1->pointer == ec->wp2->pointer);}} | |
386 | |
387 | |
388 int _WeakPointer_Equal( wp1, wp2 ) | |
389 WeakPointer* wp1; | |
390 WeakPointer* wp2; | |
391 { | |
392 EqualClosure ec; | |
393 | |
394 ec.wp1 = wp1; | |
395 ec.wp2 = wp2; | |
396 return (int) GC_call_with_alloc_lock( EqualWithLock, &ec );} | |
397 | |
398 | |
399 int _WeakPointer_Hash( wp ) | |
400 WeakPointer* wp; | |
401 { | |
402 return (int) _WeakPointer_Pointer( wp );} | |
403 | |
404 | |
405 /************************************************************************** | |
406 | |
407 Implementations of the template class CleanUp from WeakPointer.h | |
408 | |
409 ***************************************************************************/ | |
410 | |
411 typedef struct Closure { | |
412 void (*c) PROTO(( void* d, void* t )); | |
413 ptrdiff_t t_offset; | |
414 void* d; | |
415 } Closure; | |
416 | |
417 | |
418 static void _CleanUp_CallClosure( obj, data ) | |
419 void* obj; | |
420 void* data; | |
421 { | |
422 Closure* closure = (Closure*) data; | |
423 closure->c( closure->d, (char*) obj + closure->t_offset );} | |
424 | |
425 | |
426 void _CleanUp_Set( t, c, d ) | |
427 void* t; | |
428 void (*c) PROTO(( void* d, void* t )); | |
429 void* d; | |
430 { | |
431 void* base = GC_base( t ); | |
432 Descriptor* desc = DESCRIPTOR( t ); | |
433 | |
434 if (c == 0) { | |
435 GC_REGISTER_FINALIZER_IGNORE_SELF( base, 0, 0, 0, 0 ); | |
436 desc->has_finalizer = 0;} | |
437 else { | |
438 Closure* closure = (Closure*) GC_MALLOC( sizeof( Closure ) ); | |
439 closure->c = c; | |
440 closure->t_offset = (char*) t - (char*) base; | |
441 closure->d = d; | |
442 GC_REGISTER_FINALIZER_IGNORE_SELF( base, _CleanUp_CallClosure, | |
443 closure, 0, 0 ); | |
444 desc->has_finalizer = 1;}} | |
445 | |
446 | |
447 void _CleanUp_Call( t ) | |
448 void* t; | |
449 { | |
450 /* ? Aren't we supposed to deactivate weak pointers to t too? | |
451 Why? */ | |
452 void* base = GC_base( t ); | |
453 void* d; | |
454 GC_finalization_proc f; | |
455 | |
456 GC_REGISTER_FINALIZER( base, 0, 0, &f, &d ); | |
457 f( base, d );} | |
458 | |
459 | |
460 typedef struct QueueElem { | |
461 void* o; | |
462 GC_finalization_proc f; | |
463 void* d; | |
464 struct QueueElem* next; | |
465 } QueueElem; | |
466 | |
467 | |
468 void* _CleanUp_Queue_NewHead() | |
469 { | |
470 return GC_MALLOC( sizeof( QueueElem ) );} | |
471 | |
472 | |
473 static void _CleanUp_Queue_Enqueue( obj, data ) | |
474 void* obj; | |
475 void* data; | |
476 { | |
477 QueueElem* q = (QueueElem*) data; | |
478 QueueElem* head = q->next; | |
479 | |
480 q->o = obj; | |
481 q->next = head->next; | |
482 head->next = q;} | |
483 | |
484 | |
485 void _CleanUp_Queue_Set( h, t ) | |
486 void* h; | |
487 void* t; | |
488 { | |
489 QueueElem* head = (QueueElem*) h; | |
490 void* base = GC_base( t ); | |
491 void* d; | |
492 GC_finalization_proc f; | |
493 QueueElem* q = (QueueElem*) GC_MALLOC( sizeof( QueueElem ) ); | |
494 | |
495 GC_REGISTER_FINALIZER( base, _CleanUp_Queue_Enqueue, q, &f, &d ); | |
496 q->f = f; | |
497 q->d = d; | |
498 q->next = head;} | |
499 | |
500 | |
501 int _CleanUp_Queue_Call( h ) | |
502 void* h; | |
503 { | |
504 QueueElem* head = (QueueElem*) h; | |
505 QueueElem* q = head->next; | |
506 | |
507 if (q == 0) { | |
508 return 0;} | |
509 else { | |
510 head->next = q->next; | |
511 q->next = 0; | |
512 if (q->f != 0) q->f( q->o, q->d ); | |
513 return 1;}} | |
514 | |
515 | |
516 |