Back to index

plt-scheme  4.2.1
gc_cpp.h
Go to the documentation of this file.
00001 #ifndef GC_CPP_H
00002 #define GC_CPP_H
00003 /****************************************************************************
00004 Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
00005  
00006 THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00007 OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00008  
00009 Permission is hereby granted to use or copy this program for any
00010 purpose, provided the above notices are retained on all copies.
00011 Permission to modify the code and to distribute modified code is
00012 granted, provided the above notices are retained, and a notice that
00013 the code was modified is included with the above copyright notice.
00014 ****************************************************************************
00015 
00016 C++ Interface to the Boehm Collector
00017 
00018     John R. Ellis and Jesse Hull 
00019 
00020 This interface provides access to the Boehm collector.  It provides
00021 basic facilities similar to those described in "Safe, Efficient
00022 Garbage Collection for C++", by John R. Elis and David L. Detlefs
00023 (ftp://ftp.parc.xerox.com/pub/ellis/gc).
00024 
00025 All heap-allocated objects are either "collectable" or
00026 "uncollectable".  Programs must explicitly delete uncollectable
00027 objects, whereas the garbage collector will automatically delete
00028 collectable objects when it discovers them to be inaccessible.
00029 Collectable objects may freely point at uncollectable objects and vice
00030 versa.
00031 
00032 Objects allocated with the built-in "::operator new" are uncollectable.
00033 
00034 Objects derived from class "gc" are collectable.  For example:
00035 
00036     class A: public gc {...};
00037     A* a = new A;       // a is collectable. 
00038 
00039 Collectable instances of non-class types can be allocated using the GC
00040 (or UseGC) placement:
00041 
00042     typedef int A[ 10 ];
00043     A* a = new (GC) A;
00044 
00045 Uncollectable instances of classes derived from "gc" can be allocated
00046 using the NoGC placement:
00047 
00048     class A: public gc {...};
00049     A* a = new (NoGC) A;   // a is uncollectable.
00050 
00051 Both uncollectable and collectable objects can be explicitly deleted
00052 with "delete", which invokes an object's destructors and frees its
00053 storage immediately.
00054 
00055 A collectable object may have a clean-up function, which will be
00056 invoked when the collector discovers the object to be inaccessible.
00057 An object derived from "gc_cleanup" or containing a member derived
00058 from "gc_cleanup" has a default clean-up function that invokes the
00059 object's destructors.  Explicit clean-up functions may be specified as
00060 an additional placement argument:
00061 
00062     A* a = ::new (GC, MyCleanup) A;
00063 
00064 An object is considered "accessible" by the collector if it can be
00065 reached by a path of pointers from static variables, automatic
00066 variables of active functions, or from some object with clean-up
00067 enabled; pointers from an object to itself are ignored.
00068 
00069 Thus, if objects A and B both have clean-up functions, and A points at
00070 B, B is considered accessible.  After A's clean-up is invoked and its
00071 storage released, B will then become inaccessible and will have its
00072 clean-up invoked.  If A points at B and B points to A, forming a
00073 cycle, then that's considered a storage leak, and neither will be
00074 collectable.  See the interface gc.h for low-level facilities for
00075 handling such cycles of objects with clean-up.
00076 
00077 The collector cannot guarantee that it will find all inaccessible
00078 objects.  In practice, it finds almost all of them.
00079 
00080 
00081 Cautions:
00082 
00083 1. Be sure the collector has been augmented with "make c++".
00084 
00085 2.  If your compiler supports the new "operator new[]" syntax, then
00086 add -DGC_OPERATOR_NEW_ARRAY to the Makefile.
00087 
00088 If your compiler doesn't support "operator new[]", beware that an
00089 array of type T, where T is derived from "gc", may or may not be
00090 allocated as a collectable object (it depends on the compiler).  Use
00091 the explicit GC placement to make the array collectable.  For example:
00092 
00093     class A: public gc {...};
00094     A* a1 = new A[ 10 ];        // collectable or uncollectable?
00095     A* a2 = new (GC) A[ 10 ];   // collectable
00096 
00097 3. The destructors of collectable arrays of objects derived from
00098 "gc_cleanup" will not be invoked properly.  For example:
00099 
00100     class A: public gc_cleanup {...};
00101     A* a = new (GC) A[ 10 ];    // destructors not invoked correctly
00102 
00103 Typically, only the destructor for the first element of the array will
00104 be invoked when the array is garbage-collected.  To get all the
00105 destructors of any array executed, you must supply an explicit
00106 clean-up function:
00107 
00108     A* a = new (GC, MyCleanUp) A[ 10 ];
00109 
00110 (Implementing clean-up of arrays correctly, portably, and in a way
00111 that preserves the correct exception semantics requires a language
00112 extension, e.g. the "gc" keyword.)
00113 
00114 4. Compiler bugs:
00115 
00116 * Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
00117 destructors of classes derived from gc_cleanup won't be invoked.
00118 You'll have to explicitly register a clean-up function with
00119 new-placement syntax.
00120 
00121 * Evidently cfront 3.0 does not allow destructors to be explicitly
00122 invoked using the ANSI-conforming syntax t->~T().  If you're using
00123 cfront 3.0, you'll have to comment out the class gc_cleanup, which
00124 uses explicit invocation.
00125 
00126 5. GC name conflicts:
00127 
00128 Many other systems seem to use the identifier "GC" as an abbreviation
00129 for "Graphics Context".  Since version 5.0, GC placement has been replaced
00130 by UseGC.  GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
00131 
00132 ****************************************************************************/
00133 
00134 #include "gc.h"
00135 
00136 #ifndef THINK_CPLUS
00137 #  define GC_cdecl
00138 #else
00139 #  define GC_cdecl _cdecl
00140 #endif
00141 
00142 #if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \
00143     && !defined(_ENABLE_ARRAYNEW) /* Digimars */ \
00144     && (defined(__BORLANDC__) && (__BORLANDC__ < 0x450) \
00145        || (defined(__GNUC__) && \
00146            (__GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 6)) \
00147        || (defined(__WATCOMC__) && __WATCOMC__ < 1050))
00148 #   define GC_NO_OPERATOR_NEW_ARRAY
00149 #endif
00150 
00151 #if !defined(GC_NO_OPERATOR_NEW_ARRAY) && !defined(GC_OPERATOR_NEW_ARRAY)
00152 #   define GC_OPERATOR_NEW_ARRAY
00153 #endif
00154 
00155 #if    ! defined ( __BORLANDC__ )  /* Confuses the Borland compiler. */ \
00156     && ! defined ( __sgi )
00157 #  define GC_PLACEMENT_DELETE
00158 #endif
00159 
00160 enum GCPlacement {UseGC,
00161 #ifndef GC_NAME_CONFLICT
00162                 GC=UseGC,
00163 #endif
00164                   NoGC, PointerFreeGC};
00165 
00166 class gc {public:
00167     inline void* operator new( size_t size );
00168     inline void* operator new( size_t size, GCPlacement gcp );
00169     inline void* operator new( size_t size, void *p );
00170        /* Must be redefined here, since the other overloadings */
00171        /* hide the global definition.                          */
00172     inline void operator delete( void* obj );
00173 #   ifdef GC_PLACEMENT_DELETE  
00174       inline void operator delete( void*, void* );
00175 #   endif
00176 
00177 #ifdef GC_OPERATOR_NEW_ARRAY
00178     inline void* operator new[]( size_t size );
00179     inline void* operator new[]( size_t size, GCPlacement gcp );
00180     inline void* operator new[]( size_t size, void *p );
00181     inline void operator delete[]( void* obj );
00182 #   ifdef GC_PLACEMENT_DELETE
00183       inline void operator delete[]( void*, void* );
00184 #   endif
00185 #endif /* GC_OPERATOR_NEW_ARRAY */
00186     };    
00187     /*
00188     Instances of classes derived from "gc" will be allocated in the 
00189     collected heap by default, unless an explicit NoGC placement is
00190     specified. */
00191 
00192 class gc_cleanup: virtual public gc {public:
00193     inline gc_cleanup();
00194     inline virtual ~gc_cleanup();
00195 private:
00196     inline static void GC_cdecl cleanup( void* obj, void* clientData );};
00197     /*
00198     Instances of classes derived from "gc_cleanup" will be allocated
00199     in the collected heap by default.  When the collector discovers an
00200     inaccessible object derived from "gc_cleanup" or containing a
00201     member derived from "gc_cleanup", its destructors will be
00202     invoked. */
00203 
00204 extern "C" {typedef void (*GCCleanUpFunc)( void* obj, void* clientData );}
00205 
00206 #ifdef _MSC_VER
00207   // Disable warning that "no matching operator delete found; memory will
00208   // not be freed if initialization throws an exception"
00209 # pragma warning(disable:4291)
00210 #endif
00211 
00212 inline void* operator new( 
00213     size_t size, 
00214     GCPlacement gcp,
00215     GCCleanUpFunc cleanup = 0,
00216     void* clientData = 0 );
00217     /*
00218     Allocates a collectable or uncollected object, according to the
00219     value of "gcp".
00220 
00221     For collectable objects, if "cleanup" is non-null, then when the
00222     allocated object "obj" becomes inaccessible, the collector will
00223     invoke the function "cleanup( obj, clientData )" but will not
00224     invoke the object's destructors.  It is an error to explicitly
00225     delete an object allocated with a non-null "cleanup".
00226 
00227     It is an error to specify a non-null "cleanup" with NoGC or for
00228     classes derived from "gc_cleanup" or containing members derived
00229     from "gc_cleanup". */
00230 
00231 
00232 #ifdef _MSC_VER
00233 
00239  void *operator new[]( size_t size );
00240  
00241  void operator delete[](void* obj);
00242 
00243  void* operator new( size_t size);
00244 
00245  void operator delete(void* obj);
00246 
00247  // This new operator is used by VC++ in case of Debug builds !
00248  void* operator new(  size_t size,
00249                     int ,//nBlockUse,
00250                     const char * szFileName,
00251                     int nLine );
00252 #endif /* _MSC_VER */
00253 
00254 
00255 #ifdef GC_OPERATOR_NEW_ARRAY
00256 
00257 inline void* operator new[](
00258     size_t size, 
00259     GCPlacement gcp,
00260     GCCleanUpFunc cleanup = 0,
00261     void* clientData = 0 );
00262     /*
00263     The operator new for arrays, identical to the above. */
00264 
00265 #endif /* GC_OPERATOR_NEW_ARRAY */
00266 
00267 /****************************************************************************
00268 
00269 Inline implementation
00270 
00271 ****************************************************************************/
00272 
00273 inline void* gc::operator new( size_t size ) {
00274     return GC_MALLOC( size );}
00275     
00276 inline void* gc::operator new( size_t size, GCPlacement gcp ) {
00277     if (gcp == UseGC) 
00278         return GC_MALLOC( size );
00279     else if (gcp == PointerFreeGC)
00280        return GC_MALLOC_ATOMIC( size );
00281     else
00282         return GC_MALLOC_UNCOLLECTABLE( size );}
00283 
00284 inline void* gc::operator new( size_t size, void *p ) {
00285     return p;}
00286 
00287 inline void gc::operator delete( void* obj ) {
00288     GC_FREE( obj );}
00289     
00290 #ifdef GC_PLACEMENT_DELETE
00291   inline void gc::operator delete( void*, void* ) {}
00292 #endif
00293 
00294 #ifdef GC_OPERATOR_NEW_ARRAY
00295 
00296 inline void* gc::operator new[]( size_t size ) {
00297     return gc::operator new( size );}
00298     
00299 inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
00300     return gc::operator new( size, gcp );}
00301 
00302 inline void* gc::operator new[]( size_t size, void *p ) {
00303     return p;}
00304 
00305 inline void gc::operator delete[]( void* obj ) {
00306     gc::operator delete( obj );}
00307 
00308 #ifdef GC_PLACEMENT_DELETE
00309   inline void gc::operator delete[]( void*, void* ) {}
00310 #endif
00311     
00312 #endif /* GC_OPERATOR_NEW_ARRAY */
00313 
00314 
00315 inline gc_cleanup::~gc_cleanup() {
00316     GC_register_finalizer_ignore_self( GC_base(this), 0, 0, 0, 0 );}
00317 
00318 inline void gc_cleanup::cleanup( void* obj, void* displ ) {
00319     ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
00320 
00321 inline gc_cleanup::gc_cleanup() {
00322     GC_finalization_proc oldProc;
00323     void* oldData;
00324     void* base = GC_base( (void *) this );
00325     if (0 != base)  {
00326       // Don't call the debug version, since this is a real base address.
00327       GC_register_finalizer_ignore_self( 
00328         base, (GC_finalization_proc)cleanup, (void*) ((char*) this - (char*) base), 
00329         &oldProc, &oldData );
00330       if (0 != oldProc) {
00331         GC_register_finalizer_ignore_self( base, oldProc, oldData, 0, 0 );}}}
00332 
00333 inline void* operator new( 
00334     size_t size, 
00335     GCPlacement gcp,
00336     GCCleanUpFunc cleanup,
00337     void* clientData )
00338 {
00339     void* obj;
00340 
00341     if (gcp == UseGC) {
00342         obj = GC_MALLOC( size );
00343         if (cleanup != 0) 
00344             GC_REGISTER_FINALIZER_IGNORE_SELF( 
00345                 obj, cleanup, clientData, 0, 0 );}
00346     else if (gcp == PointerFreeGC) {
00347         obj = GC_MALLOC_ATOMIC( size );}
00348     else {
00349         obj = GC_MALLOC_UNCOLLECTABLE( size );};
00350     return obj;}
00351         
00352 
00353 #ifdef GC_OPERATOR_NEW_ARRAY
00354 
00355 inline void* operator new[]( 
00356     size_t size, 
00357     GCPlacement gcp,
00358     GCCleanUpFunc cleanup,
00359     void* clientData )
00360 {
00361     return ::operator new( size, gcp, cleanup, clientData );}
00362 
00363 #endif /* GC_OPERATOR_NEW_ARRAY */
00364 
00365 
00366 #endif /* GC_CPP_H */
00367