Back to index

lightning-sunbird  0.9+nobinonly
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     Last modified on Mon Jul 24 15:43:42 PDT 1995 by ellis
00020 
00021 This interface provides access to the Boehm collector.  It provides
00022 basic facilities similar to those described in "Safe, Efficient
00023 Garbage Collection for C++", by John R. Elis and David L. Detlefs
00024 (ftp.parc.xerox.com:/pub/ellis/gc).
00025 
00026 All heap-allocated objects are either "collectable" or
00027 "uncollectable".  Programs must explicitly delete uncollectable
00028 objects, whereas the garbage collector will automatically delete
00029 collectable objects when it discovers them to be inaccessible.
00030 Collectable objects may freely point at uncollectable objects and vice
00031 versa.
00032 
00033 Objects allocated with the built-in "::operator new" are uncollectable.
00034 
00035 Objects derived from class "gc" are collectable.  For example:
00036 
00037     class A: public gc {...};
00038     A* a = new A;       // a is collectable. 
00039 
00040 Collectable instances of non-class types can be allocated using the GC
00041 placement:
00042 
00043     typedef int A[ 10 ];
00044     A* a = new (GC) A;
00045 
00046 Uncollectable instances of classes derived from "gc" can be allocated
00047 using the NoGC placement:
00048 
00049     class A: public gc {...};
00050     A* a = new (NoGC) A;   // a is uncollectable.
00051 
00052 Both uncollectable and collectable objects can be explicitly deleted
00053 with "delete", which invokes an object's destructors and frees its
00054 storage immediately.
00055 
00056 A collectable object may have a clean-up function, which will be
00057 invoked when the collector discovers the object to be inaccessible.
00058 An object derived from "gc_cleanup" or containing a member derived
00059 from "gc_cleanup" has a default clean-up function that invokes the
00060 object's destructors.  Explicit clean-up functions may be specified as
00061 an additional placement argument:
00062 
00063     A* a = ::new (GC, MyCleanup) A;
00064 
00065 An object is considered "accessible" by the collector if it can be
00066 reached by a path of pointers from static variables, automatic
00067 variables of active functions, or from some object with clean-up
00068 enabled; pointers from an object to itself are ignored.
00069 
00070 Thus, if objects A and B both have clean-up functions, and A points at
00071 B, B is considered accessible.  After A's clean-up is invoked and its
00072 storage released, B will then become inaccessible and will have its
00073 clean-up invoked.  If A points at B and B points to A, forming a
00074 cycle, then that's considered a storage leak, and neither will be
00075 collectable.  See the interface gc.h for low-level facilities for
00076 handling such cycles of objects with clean-up.
00077 
00078 The collector cannot guarrantee that it will find all inaccessible
00079 objects.  In practice, it finds almost all of them.
00080 
00081 
00082 Cautions:
00083 
00084 1. Be sure the collector has been augmented with "make c++".
00085 
00086 2.  If your compiler supports the new "operator new[]" syntax, then
00087 add -DOPERATOR_NEW_ARRAY to the Makefile.
00088 
00089 If your compiler doesn't support "operator new[]", beware that an
00090 array of type T, where T is derived from "gc", may or may not be
00091 allocated as a collectable object (it depends on the compiler).  Use
00092 the explicit GC placement to make the array collectable.  For example:
00093 
00094     class A: public gc {...};
00095     A* a1 = new A[ 10 ];        // collectable or uncollectable?
00096     A* a2 = new (GC) A[ 10 ];   // collectable
00097 
00098 3. The destructors of collectable arrays of objects derived from
00099 "gc_cleanup" will not be invoked properly.  For example:
00100 
00101     class A: public gc_cleanup {...};
00102     A* a = new (GC) A[ 10 ];    // destructors not invoked correctly
00103 
00104 Typically, only the destructor for the first element of the array will
00105 be invoked when the array is garbage-collected.  To get all the
00106 destructors of any array executed, you must supply an explicit
00107 clean-up function:
00108 
00109     A* a = new (GC, MyCleanUp) A[ 10 ];
00110 
00111 (Implementing clean-up of arrays correctly, portably, and in a way
00112 that preserves the correct exception semantics requires a language
00113 extension, e.g. the "gc" keyword.)
00114 
00115 4. Compiler bugs:
00116 
00117 * Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
00118 destructors of classes derived from gc_cleanup won't be invoked.
00119 You'll have to explicitly register a clean-up function with
00120 new-placement syntax.
00121 
00122 * Evidently cfront 3.0 does not allow destructors to be explicitly
00123 invoked using the ANSI-conforming syntax t->~T().  If you're using
00124 cfront 3.0, you'll have to comment out the class gc_cleanup, which
00125 uses explicit invocation.
00126 
00127 ****************************************************************************/
00128 
00129 #include "gc.h"
00130 
00131 #ifndef THINK_CPLUS
00132 #define _cdecl
00133 #endif
00134 
00135 #if ! defined( OPERATOR_NEW_ARRAY ) \
00136     && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6) \
00137         || __WATCOMC__ >= 1050)
00138 #   define OPERATOR_NEW_ARRAY
00139 #endif
00140 
00141 enum GCPlacement {GC, NoGC, PointerFreeGC};
00142 
00143 class gc {public:
00144     inline void* operator new( size_t size );
00145     inline void* operator new( size_t size, GCPlacement gcp );
00146     inline void operator delete( void* obj );
00147 
00148 #ifdef OPERATOR_NEW_ARRAY
00149     inline void* operator new[]( size_t size );
00150     inline void* operator new[]( size_t size, GCPlacement gcp );
00151     inline void operator delete[]( void* obj );
00152 #endif /* OPERATOR_NEW_ARRAY */
00153     };    
00154     /*
00155     Instances of classes derived from "gc" will be allocated in the 
00156     collected heap by default, unless an explicit NoGC placement is
00157     specified. */
00158 
00159 class gc_cleanup: virtual public gc {public:
00160     inline gc_cleanup();
00161     inline virtual ~gc_cleanup();
00162 private:
00163     inline static void _cdecl cleanup( void* obj, void* clientData );};
00164     /*
00165     Instances of classes derived from "gc_cleanup" will be allocated
00166     in the collected heap by default.  When the collector discovers an
00167     inaccessible object derived from "gc_cleanup" or containing a
00168     member derived from "gc_cleanup", its destructors will be
00169     invoked. */
00170 
00171 extern "C" {typedef void (*GCCleanUpFunc)( void* obj, void* clientData );}
00172 
00173 inline void* operator new( 
00174     size_t size, 
00175     GCPlacement gcp,
00176     GCCleanUpFunc cleanup = 0,
00177     void* clientData = 0 );
00178     /*
00179     Allocates a collectable or uncollected object, according to the
00180     value of "gcp".
00181 
00182     For collectable objects, if "cleanup" is non-null, then when the
00183     allocated object "obj" becomes inaccessible, the collector will
00184     invoke the function "cleanup( obj, clientData )" but will not
00185     invoke the object's destructors.  It is an error to explicitly
00186     delete an object allocated with a non-null "cleanup".
00187 
00188     It is an error to specify a non-null "cleanup" with NoGC or for
00189     classes derived from "gc_cleanup" or containing members derived
00190     from "gc_cleanup". */
00191 
00192 #ifdef OPERATOR_NEW_ARRAY
00193 
00194 inline void* operator new[](
00195     size_t size, 
00196     GCPlacement gcp,
00197     GCCleanUpFunc cleanup = 0,
00198     void* clientData = 0 );
00199     /*
00200     The operator new for arrays, identical to the above. */
00201 
00202 #endif /* OPERATOR_NEW_ARRAY */
00203 
00204 /****************************************************************************
00205 
00206 Inline implementation
00207 
00208 ****************************************************************************/
00209 
00210 inline void* gc::operator new( size_t size ) {
00211     return GC_MALLOC( size );}
00212     
00213 inline void* gc::operator new( size_t size, GCPlacement gcp ) {
00214     if (gcp == GC) 
00215         return GC_MALLOC( size );
00216     else if (gcp == PointerFreeGC)
00217        return GC_MALLOC_ATOMIC( size );
00218     else
00219         return GC_MALLOC_UNCOLLECTABLE( size );}
00220 
00221 inline void gc::operator delete( void* obj ) {
00222     GC_FREE( obj );}
00223     
00224 
00225 #ifdef OPERATOR_NEW_ARRAY
00226 
00227 inline void* gc::operator new[]( size_t size ) {
00228     return gc::operator new( size );}
00229     
00230 inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
00231     return gc::operator new( size, gcp );}
00232 
00233 inline void gc::operator delete[]( void* obj ) {
00234     gc::operator delete( obj );}
00235     
00236 #endif /* OPERATOR_NEW_ARRAY */
00237 
00238 
00239 inline gc_cleanup::~gc_cleanup() {
00240     GC_REGISTER_FINALIZER_IGNORE_SELF( GC_base(this), 0, 0, 0, 0 );}
00241 
00242 inline void gc_cleanup::cleanup( void* obj, void* displ ) {
00243     ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
00244 
00245 inline gc_cleanup::gc_cleanup() {
00246     GC_finalization_proc oldProc;
00247     void* oldData;
00248     void* base = GC_base( (void *) this );
00249     if (0 == base) return;
00250     GC_REGISTER_FINALIZER_IGNORE_SELF( 
00251         base, cleanup, (void*) ((char*) this - (char*) base), 
00252         &oldProc, &oldData );
00253     if (0 != oldProc) {
00254         GC_REGISTER_FINALIZER_IGNORE_SELF( base, oldProc, oldData, 0, 0 );}}
00255 
00256 inline void* operator new( 
00257     size_t size, 
00258     GCPlacement gcp,
00259     GCCleanUpFunc cleanup,
00260     void* clientData )
00261 {
00262     void* obj;
00263 
00264     if (gcp == GC) {
00265         obj = GC_MALLOC( size );
00266         if (cleanup != 0) 
00267             GC_REGISTER_FINALIZER_IGNORE_SELF( 
00268                 obj, cleanup, clientData, 0, 0 );}
00269     else if (gcp == PointerFreeGC) {
00270         obj = GC_MALLOC_ATOMIC( size );}
00271     else {
00272         obj = GC_MALLOC_UNCOLLECTABLE( size );};
00273     return obj;}
00274         
00275 
00276 #ifdef OPERATOR_NEW_ARRAY
00277 
00278 inline void* operator new[]( 
00279     size_t size, 
00280     GCPlacement gcp,
00281     GCCleanUpFunc cleanup,
00282     void* clientData )
00283 {
00284     return ::operator new( size, gcp, cleanup, clientData );}
00285 
00286 #endif /* OPERATOR_NEW_ARRAY */
00287 
00288 
00289 #endif /* GC_CPP_H */
00290