root/gc/gcc_support.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nelts
  2. padding
  3. BI_header
  4. has_weak_pointers
  5. has_finalizer
  6. BITSPERBYTE
  7. Descriptor
  8. size
  9. __default_new_handler
  10. size
  11. o
  12. handler
  13. size
  14. size
  15. size
  16. __default_new_handler
  17. size
  18. o
  19. handler
  20. size
  21. __default_new_handler
  22. size
  23. o
  24. handler
  25. size
  26. size
  27. size
  28. size
  29. o
  30. o
  31. data
  32. o
  33. o
  34. o
  35. d
  36. o
  37. o
  38. call_destructor
  39. d
  40. has_finalizer
  41. o
  42. o
  43. data
  44. o
  45. o
  46. element_size
  47. o
  48. size
  49. p
  50. first_p
  51. size
  52. first_elem
  53. d
  54. first_elem
  55. d
  56. element_size
  57. BI_header
  58. o
  59. o
  60. call_array_destructor
  61. d
  62. element_size
  63. has_finalizer
  64. o
  65. o
  66. o
  67. o
  68. o
  69. o
  70. pointer
  71. WeakPointer
  72. t
  73. t
  74. t
  75. GC_MALLOC_ATOMIC
  76. base
  77. t
  78. has_weak_pointers
  79. pointer
  80. base
  81. wp
  82. wp
  83. pointer
  84. pointer
  85. wp
  86. PointerWithLock
  87. wp
  88. wp1
  89. wp2
  90. EqualClosure
  91. ec
  92. wp2
  93. pointer
  94. wp1
  95. wp1
  96. wp2
  97. ec
  98. wp1
  99. wp2
  100. EqualWithLock
  101. ec
  102. wp
  103. wp
  104. PROTO
  105. t_offset
  106. d
  107. Closure
  108. obj
  109. obj
  110. data
  111. data
  112. d
  113. t_offset
  114. t
  115. c
  116. t
  117. PROTO
  118. d
  119. t
  120. t
  121. base
  122. has_finalizer
  123. GC_MALLOC
  124. c
  125. base
  126. d
  127. base
  128. _CleanUp_CallClosure
  129. closure
  130. has_finalizer
  131. t
  132. t
  133. d
  134. f
  135. base
  136. f
  137. d
  138. base
  139. d
  140. o
  141. f
  142. d
  143. next
  144. QueueElem
  145. GC_MALLOC
  146. obj
  147. obj
  148. data
  149. data
  150. next
  151. obj
  152. next
  153. q
  154. h
  155. h
  156. t
  157. h
  158. t
  159. d
  160. f
  161. GC_MALLOC
  162. base
  163. _CleanUp_Queue_Enqueue
  164. q
  165. f
  166. d
  167. f
  168. d
  169. head
  170. h
  171. h
  172. next
  173. q
  174. next
  175. next
  176. o
  177. d

   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 

/* [<][>][^][v][top][bottom][index][help] */