Annotation of OpenXM/src/kan96xx/gc-4.14/gcc_support.c, Revision 1.1.1.1
1.1 maekawa 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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>