[BACK]Return to gcc_support.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Annotation of OpenXM_contrib2/asir2000/gc/gcc_support.c, Revision 1.3

1.1       noro        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>