| 1 | #ifndef GC_CPP_H
|
|---|
| 2 | #define GC_CPP_H
|
|---|
| 3 | /****************************************************************************
|
|---|
| 4 | Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
|---|
| 5 |
|
|---|
| 6 | THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
|---|
| 7 | OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
|---|
| 8 |
|
|---|
| 9 | Permission is hereby granted to use or copy this program for any
|
|---|
| 10 | purpose, provided the above notices are retained on all copies.
|
|---|
| 11 | Permission to modify the code and to distribute modified code is
|
|---|
| 12 | granted, provided the above notices are retained, and a notice that
|
|---|
| 13 | the code was modified is included with the above copyright notice.
|
|---|
| 14 | ****************************************************************************
|
|---|
| 15 |
|
|---|
| 16 | C++ Interface to the Boehm Collector
|
|---|
| 17 |
|
|---|
| 18 | John R. Ellis and Jesse Hull
|
|---|
| 19 |
|
|---|
| 20 | This interface provides access to the Boehm collector. It provides
|
|---|
| 21 | basic facilities similar to those described in "Safe, Efficient
|
|---|
| 22 | Garbage Collection for C++", by John R. Elis and David L. Detlefs
|
|---|
| 23 | (ftp://ftp.parc.xerox.com/pub/ellis/gc).
|
|---|
| 24 |
|
|---|
| 25 | All heap-allocated objects are either "collectable" or
|
|---|
| 26 | "uncollectable". Programs must explicitly delete uncollectable
|
|---|
| 27 | objects, whereas the garbage collector will automatically delete
|
|---|
| 28 | collectable objects when it discovers them to be inaccessible.
|
|---|
| 29 | Collectable objects may freely point at uncollectable objects and vice
|
|---|
| 30 | versa.
|
|---|
| 31 |
|
|---|
| 32 | Objects allocated with the built-in "::operator new" are uncollectable.
|
|---|
| 33 |
|
|---|
| 34 | Objects derived from class "gc" are collectable. For example:
|
|---|
| 35 |
|
|---|
| 36 | class A: public gc {...};
|
|---|
| 37 | A* a = new A; // a is collectable.
|
|---|
| 38 |
|
|---|
| 39 | Collectable instances of non-class types can be allocated using the GC
|
|---|
| 40 | (or UseGC) placement:
|
|---|
| 41 |
|
|---|
| 42 | typedef int A[ 10 ];
|
|---|
| 43 | A* a = new (GC) A;
|
|---|
| 44 |
|
|---|
| 45 | Uncollectable instances of classes derived from "gc" can be allocated
|
|---|
| 46 | using the NoGC placement:
|
|---|
| 47 |
|
|---|
| 48 | class A: public gc {...};
|
|---|
| 49 | A* a = new (NoGC) A; // a is uncollectable.
|
|---|
| 50 |
|
|---|
| 51 | Both uncollectable and collectable objects can be explicitly deleted
|
|---|
| 52 | with "delete", which invokes an object's destructors and frees its
|
|---|
| 53 | storage immediately.
|
|---|
| 54 |
|
|---|
| 55 | A collectable object may have a clean-up function, which will be
|
|---|
| 56 | invoked when the collector discovers the object to be inaccessible.
|
|---|
| 57 | An object derived from "gc_cleanup" or containing a member derived
|
|---|
| 58 | from "gc_cleanup" has a default clean-up function that invokes the
|
|---|
| 59 | object's destructors. Explicit clean-up functions may be specified as
|
|---|
| 60 | an additional placement argument:
|
|---|
| 61 |
|
|---|
| 62 | A* a = ::new (GC, MyCleanup) A;
|
|---|
| 63 |
|
|---|
| 64 | An object is considered "accessible" by the collector if it can be
|
|---|
| 65 | reached by a path of pointers from static variables, automatic
|
|---|
| 66 | variables of active functions, or from some object with clean-up
|
|---|
| 67 | enabled; pointers from an object to itself are ignored.
|
|---|
| 68 |
|
|---|
| 69 | Thus, if objects A and B both have clean-up functions, and A points at
|
|---|
| 70 | B, B is considered accessible. After A's clean-up is invoked and its
|
|---|
| 71 | storage released, B will then become inaccessible and will have its
|
|---|
| 72 | clean-up invoked. If A points at B and B points to A, forming a
|
|---|
| 73 | cycle, then that's considered a storage leak, and neither will be
|
|---|
| 74 | collectable. See the interface gc.h for low-level facilities for
|
|---|
| 75 | handling such cycles of objects with clean-up.
|
|---|
| 76 |
|
|---|
| 77 | The collector cannot guarantee that it will find all inaccessible
|
|---|
| 78 | objects. In practice, it finds almost all of them.
|
|---|
| 79 |
|
|---|
| 80 |
|
|---|
| 81 | Cautions:
|
|---|
| 82 |
|
|---|
| 83 | 1. Be sure the collector has been augmented with "make c++".
|
|---|
| 84 |
|
|---|
| 85 | 2. If your compiler supports the new "operator new[]" syntax, then
|
|---|
| 86 | add -DGC_OPERATOR_NEW_ARRAY to the Makefile.
|
|---|
| 87 |
|
|---|
| 88 | If your compiler doesn't support "operator new[]", beware that an
|
|---|
| 89 | array of type T, where T is derived from "gc", may or may not be
|
|---|
| 90 | allocated as a collectable object (it depends on the compiler). Use
|
|---|
| 91 | the explicit GC placement to make the array collectable. For example:
|
|---|
| 92 |
|
|---|
| 93 | class A: public gc {...};
|
|---|
| 94 | A* a1 = new A[ 10 ]; // collectable or uncollectable?
|
|---|
| 95 | A* a2 = new (GC) A[ 10 ]; // collectable
|
|---|
| 96 |
|
|---|
| 97 | 3. The destructors of collectable arrays of objects derived from
|
|---|
| 98 | "gc_cleanup" will not be invoked properly. For example:
|
|---|
| 99 |
|
|---|
| 100 | class A: public gc_cleanup {...};
|
|---|
| 101 | A* a = new (GC) A[ 10 ]; // destructors not invoked correctly
|
|---|
| 102 |
|
|---|
| 103 | Typically, only the destructor for the first element of the array will
|
|---|
| 104 | be invoked when the array is garbage-collected. To get all the
|
|---|
| 105 | destructors of any array executed, you must supply an explicit
|
|---|
| 106 | clean-up function:
|
|---|
| 107 |
|
|---|
| 108 | A* a = new (GC, MyCleanUp) A[ 10 ];
|
|---|
| 109 |
|
|---|
| 110 | (Implementing clean-up of arrays correctly, portably, and in a way
|
|---|
| 111 | that preserves the correct exception semantics requires a language
|
|---|
| 112 | extension, e.g. the "gc" keyword.)
|
|---|
| 113 |
|
|---|
| 114 | 4. Compiler bugs:
|
|---|
| 115 |
|
|---|
| 116 | * Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
|
|---|
| 117 | destructors of classes derived from gc_cleanup won't be invoked.
|
|---|
| 118 | You'll have to explicitly register a clean-up function with
|
|---|
| 119 | new-placement syntax.
|
|---|
| 120 |
|
|---|
| 121 | * Evidently cfront 3.0 does not allow destructors to be explicitly
|
|---|
| 122 | invoked using the ANSI-conforming syntax t->~T(). If you're using
|
|---|
| 123 | cfront 3.0, you'll have to comment out the class gc_cleanup, which
|
|---|
| 124 | uses explicit invocation.
|
|---|
| 125 |
|
|---|
| 126 | 5. GC name conflicts:
|
|---|
| 127 |
|
|---|
| 128 | Many other systems seem to use the identifier "GC" as an abbreviation
|
|---|
| 129 | for "Graphics Context". Since version 5.0, GC placement has been replaced
|
|---|
| 130 | by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
|
|---|
| 131 |
|
|---|
| 132 | ****************************************************************************/
|
|---|
| 133 |
|
|---|
| 134 | #include "gc.h"
|
|---|
| 135 |
|
|---|
| 136 | #ifndef THINK_CPLUS
|
|---|
| 137 | # define GC_cdecl
|
|---|
| 138 | #else
|
|---|
| 139 | # define GC_cdecl _cdecl
|
|---|
| 140 | #endif
|
|---|
| 141 |
|
|---|
| 142 | #if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \
|
|---|
| 143 | && !defined(_ENABLE_ARRAYNEW) /* Digimars */ \
|
|---|
| 144 | && (defined(__BORLANDC__) && (__BORLANDC__ < 0x450) \
|
|---|
| 145 | || (defined(__GNUC__) && \
|
|---|
| 146 | (__GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 6)) \
|
|---|
| 147 | || (defined(__WATCOMC__) && __WATCOMC__ < 1050))
|
|---|
| 148 | # define GC_NO_OPERATOR_NEW_ARRAY
|
|---|
| 149 | #endif
|
|---|
| 150 |
|
|---|
| 151 | #if !defined(GC_NO_OPERATOR_NEW_ARRAY) && !defined(GC_OPERATOR_NEW_ARRAY)
|
|---|
| 152 | # define GC_OPERATOR_NEW_ARRAY
|
|---|
| 153 | #endif
|
|---|
| 154 |
|
|---|
| 155 | #if ! defined ( __BORLANDC__ ) /* Confuses the Borland compiler. */ \
|
|---|
| 156 | && ! defined ( __sgi )
|
|---|
| 157 | # define GC_PLACEMENT_DELETE
|
|---|
| 158 | #endif
|
|---|
| 159 |
|
|---|
| 160 | enum GCPlacement {UseGC,
|
|---|
| 161 | #ifndef GC_NAME_CONFLICT
|
|---|
| 162 | GC=UseGC,
|
|---|
| 163 | #endif
|
|---|
| 164 | NoGC, PointerFreeGC};
|
|---|
| 165 |
|
|---|
| 166 | class gc {public:
|
|---|
| 167 | inline void* operator new( size_t size );
|
|---|
| 168 | inline void* operator new( size_t size, GCPlacement gcp );
|
|---|
| 169 | inline void* operator new( size_t size, void *p );
|
|---|
| 170 | /* Must be redefined here, since the other overloadings */
|
|---|
| 171 | /* hide the global definition. */
|
|---|
| 172 | inline void operator delete( void* obj );
|
|---|
| 173 | # ifdef GC_PLACEMENT_DELETE
|
|---|
| 174 | inline void operator delete( void*, void* );
|
|---|
| 175 | # endif
|
|---|
| 176 |
|
|---|
| 177 | #ifdef GC_OPERATOR_NEW_ARRAY
|
|---|
| 178 | inline void* operator new[]( size_t size );
|
|---|
| 179 | inline void* operator new[]( size_t size, GCPlacement gcp );
|
|---|
| 180 | inline void* operator new[]( size_t size, void *p );
|
|---|
| 181 | inline void operator delete[]( void* obj );
|
|---|
| 182 | # ifdef GC_PLACEMENT_DELETE
|
|---|
| 183 | inline void operator delete[]( void*, void* );
|
|---|
| 184 | # endif
|
|---|
| 185 | #endif /* GC_OPERATOR_NEW_ARRAY */
|
|---|
| 186 | };
|
|---|
| 187 | /*
|
|---|
| 188 | Instances of classes derived from "gc" will be allocated in the
|
|---|
| 189 | collected heap by default, unless an explicit NoGC placement is
|
|---|
| 190 | specified. */
|
|---|
| 191 |
|
|---|
| 192 | class gc_cleanup: virtual public gc {public:
|
|---|
| 193 | inline gc_cleanup();
|
|---|
| 194 | inline virtual ~gc_cleanup();
|
|---|
| 195 | private:
|
|---|
| 196 | inline static void GC_cdecl cleanup( void* obj, void* clientData );};
|
|---|
| 197 | /*
|
|---|
| 198 | Instances of classes derived from "gc_cleanup" will be allocated
|
|---|
| 199 | in the collected heap by default. When the collector discovers an
|
|---|
| 200 | inaccessible object derived from "gc_cleanup" or containing a
|
|---|
| 201 | member derived from "gc_cleanup", its destructors will be
|
|---|
| 202 | invoked. */
|
|---|
| 203 |
|
|---|
| 204 | extern "C" {typedef void (*GCCleanUpFunc)( void* obj, void* clientData );}
|
|---|
| 205 |
|
|---|
| 206 | #ifdef _MSC_VER
|
|---|
| 207 | // Disable warning that "no matching operator delete found; memory will
|
|---|
| 208 | // not be freed if initialization throws an exception"
|
|---|
| 209 | # pragma warning(disable:4291)
|
|---|
| 210 | #endif
|
|---|
| 211 |
|
|---|
| 212 | inline void* operator new(
|
|---|
| 213 | size_t size,
|
|---|
| 214 | GCPlacement gcp,
|
|---|
| 215 | GCCleanUpFunc cleanup = 0,
|
|---|
| 216 | void* clientData = 0 );
|
|---|
| 217 | /*
|
|---|
| 218 | Allocates a collectable or uncollected object, according to the
|
|---|
| 219 | value of "gcp".
|
|---|
| 220 |
|
|---|
| 221 | For collectable objects, if "cleanup" is non-null, then when the
|
|---|
| 222 | allocated object "obj" becomes inaccessible, the collector will
|
|---|
| 223 | invoke the function "cleanup( obj, clientData )" but will not
|
|---|
| 224 | invoke the object's destructors. It is an error to explicitly
|
|---|
| 225 | delete an object allocated with a non-null "cleanup".
|
|---|
| 226 |
|
|---|
| 227 | It is an error to specify a non-null "cleanup" with NoGC or for
|
|---|
| 228 | classes derived from "gc_cleanup" or containing members derived
|
|---|
| 229 | from "gc_cleanup". */
|
|---|
| 230 |
|
|---|
| 231 |
|
|---|
| 232 | #ifdef _MSC_VER
|
|---|
| 233 | /** This ensures that the system default operator new[] doesn't get
|
|---|
| 234 | * undefined, which is what seems to happen on VC++ 6 for some reason
|
|---|
| 235 | * if we define a multi-argument operator new[].
|
|---|
| 236 | * There seems to be really redirect new in this environment without
|
|---|
| 237 | * including this everywhere.
|
|---|
| 238 | */
|
|---|
| 239 | void *operator new[]( size_t size );
|
|---|
| 240 |
|
|---|
| 241 | void operator delete[](void* obj);
|
|---|
| 242 |
|
|---|
| 243 | void* operator new( size_t size);
|
|---|
| 244 |
|
|---|
| 245 | void operator delete(void* obj);
|
|---|
| 246 |
|
|---|
| 247 | // This new operator is used by VC++ in case of Debug builds !
|
|---|
| 248 | void* operator new( size_t size,
|
|---|
| 249 | int ,//nBlockUse,
|
|---|
| 250 | const char * szFileName,
|
|---|
| 251 | int nLine );
|
|---|
| 252 | #endif /* _MSC_VER */
|
|---|
| 253 |
|
|---|
| 254 |
|
|---|
| 255 | #ifdef GC_OPERATOR_NEW_ARRAY
|
|---|
| 256 |
|
|---|
| 257 | inline void* operator new[](
|
|---|
| 258 | size_t size,
|
|---|
| 259 | GCPlacement gcp,
|
|---|
| 260 | GCCleanUpFunc cleanup = 0,
|
|---|
| 261 | void* clientData = 0 );
|
|---|
| 262 | /*
|
|---|
| 263 | The operator new for arrays, identical to the above. */
|
|---|
| 264 |
|
|---|
| 265 | #endif /* GC_OPERATOR_NEW_ARRAY */
|
|---|
| 266 |
|
|---|
| 267 | /****************************************************************************
|
|---|
| 268 |
|
|---|
| 269 | Inline implementation
|
|---|
| 270 |
|
|---|
| 271 | ****************************************************************************/
|
|---|
| 272 |
|
|---|
| 273 | inline void* gc::operator new( size_t size ) {
|
|---|
| 274 | return GC_MALLOC( size );}
|
|---|
| 275 |
|
|---|
| 276 | inline void* gc::operator new( size_t size, GCPlacement gcp ) {
|
|---|
| 277 | if (gcp == UseGC)
|
|---|
| 278 | return GC_MALLOC( size );
|
|---|
| 279 | else if (gcp == PointerFreeGC)
|
|---|
| 280 | return GC_MALLOC_ATOMIC( size );
|
|---|
| 281 | else
|
|---|
| 282 | return GC_MALLOC_UNCOLLECTABLE( size );}
|
|---|
| 283 |
|
|---|
| 284 | inline void* gc::operator new( size_t size, void *p ) {
|
|---|
| 285 | return p;}
|
|---|
| 286 |
|
|---|
| 287 | inline void gc::operator delete( void* obj ) {
|
|---|
| 288 | GC_FREE( obj );}
|
|---|
| 289 |
|
|---|
| 290 | #ifdef GC_PLACEMENT_DELETE
|
|---|
| 291 | inline void gc::operator delete( void*, void* ) {}
|
|---|
| 292 | #endif
|
|---|
| 293 |
|
|---|
| 294 | #ifdef GC_OPERATOR_NEW_ARRAY
|
|---|
| 295 |
|
|---|
| 296 | inline void* gc::operator new[]( size_t size ) {
|
|---|
| 297 | return gc::operator new( size );}
|
|---|
| 298 |
|
|---|
| 299 | inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
|
|---|
| 300 | return gc::operator new( size, gcp );}
|
|---|
| 301 |
|
|---|
| 302 | inline void* gc::operator new[]( size_t size, void *p ) {
|
|---|
| 303 | return p;}
|
|---|
| 304 |
|
|---|
| 305 | inline void gc::operator delete[]( void* obj ) {
|
|---|
| 306 | gc::operator delete( obj );}
|
|---|
| 307 |
|
|---|
| 308 | #ifdef GC_PLACEMENT_DELETE
|
|---|
| 309 | inline void gc::operator delete[]( void*, void* ) {}
|
|---|
| 310 | #endif
|
|---|
| 311 |
|
|---|
| 312 | #endif /* GC_OPERATOR_NEW_ARRAY */
|
|---|
| 313 |
|
|---|
| 314 |
|
|---|
| 315 | inline gc_cleanup::~gc_cleanup() {
|
|---|
| 316 | GC_register_finalizer_ignore_self( GC_base(this), 0, 0, 0, 0 );}
|
|---|
| 317 |
|
|---|
| 318 | inline void gc_cleanup::cleanup( void* obj, void* displ ) {
|
|---|
| 319 | ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
|
|---|
| 320 |
|
|---|
| 321 | inline gc_cleanup::gc_cleanup() {
|
|---|
| 322 | GC_finalization_proc oldProc;
|
|---|
| 323 | void* oldData;
|
|---|
| 324 | void* base = GC_base( (void *) this );
|
|---|
| 325 | if (0 != base) {
|
|---|
| 326 | // Don't call the debug version, since this is a real base address.
|
|---|
| 327 | GC_register_finalizer_ignore_self(
|
|---|
| 328 | base, (GC_finalization_proc)cleanup, (void*) ((char*) this - (char*) base),
|
|---|
| 329 | &oldProc, &oldData );
|
|---|
| 330 | if (0 != oldProc) {
|
|---|
| 331 | GC_register_finalizer_ignore_self( base, oldProc, oldData, 0, 0 );}}}
|
|---|
| 332 |
|
|---|
| 333 | inline void* operator new(
|
|---|
| 334 | size_t size,
|
|---|
| 335 | GCPlacement gcp,
|
|---|
| 336 | GCCleanUpFunc cleanup,
|
|---|
| 337 | void* clientData )
|
|---|
| 338 | {
|
|---|
| 339 | void* obj;
|
|---|
| 340 |
|
|---|
| 341 | if (gcp == UseGC) {
|
|---|
| 342 | obj = GC_MALLOC( size );
|
|---|
| 343 | if (cleanup != 0)
|
|---|
| 344 | GC_REGISTER_FINALIZER_IGNORE_SELF(
|
|---|
| 345 | obj, cleanup, clientData, 0, 0 );}
|
|---|
| 346 | else if (gcp == PointerFreeGC) {
|
|---|
| 347 | obj = GC_MALLOC_ATOMIC( size );}
|
|---|
| 348 | else {
|
|---|
| 349 | obj = GC_MALLOC_UNCOLLECTABLE( size );};
|
|---|
| 350 | return obj;}
|
|---|
| 351 |
|
|---|
| 352 |
|
|---|
| 353 | #ifdef GC_OPERATOR_NEW_ARRAY
|
|---|
| 354 |
|
|---|
| 355 | inline void* operator new[](
|
|---|
| 356 | size_t size,
|
|---|
| 357 | GCPlacement gcp,
|
|---|
| 358 | GCCleanUpFunc cleanup,
|
|---|
| 359 | void* clientData )
|
|---|
| 360 | {
|
|---|
| 361 | return ::operator new( size, gcp, cleanup, clientData );}
|
|---|
| 362 |
|
|---|
| 363 | #endif /* GC_OPERATOR_NEW_ARRAY */
|
|---|
| 364 |
|
|---|
| 365 |
|
|---|
| 366 | #endif /* GC_CPP_H */
|
|---|
| 367 |
|
|---|