]>
Commit | Line | Data |
---|---|---|
73ffefd0 TT |
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 | Last modified on Mon Jul 24 15:43:42 PDT 1995 by ellis | |
20 | ||
21 | This interface provides access to the Boehm collector. It provides | |
22 | basic facilities similar to those described in "Safe, Efficient | |
23 | Garbage Collection for C++", by John R. Elis and David L. Detlefs | |
24 | (ftp.parc.xerox.com:/pub/ellis/gc). | |
25 | ||
26 | All heap-allocated objects are either "collectable" or | |
27 | "uncollectable". Programs must explicitly delete uncollectable | |
28 | objects, whereas the garbage collector will automatically delete | |
29 | collectable objects when it discovers them to be inaccessible. | |
30 | Collectable objects may freely point at uncollectable objects and vice | |
31 | versa. | |
32 | ||
33 | Objects allocated with the built-in "::operator new" are uncollectable. | |
34 | ||
35 | Objects derived from class "gc" are collectable. For example: | |
36 | ||
37 | class A: public gc {...}; | |
38 | A* a = new A; // a is collectable. | |
39 | ||
40 | Collectable instances of non-class types can be allocated using the GC | |
41 | placement: | |
42 | ||
43 | typedef int A[ 10 ]; | |
44 | A* a = new (GC) A; | |
45 | ||
46 | Uncollectable instances of classes derived from "gc" can be allocated | |
47 | using the NoGC placement: | |
48 | ||
49 | class A: public gc {...}; | |
50 | A* a = new (NoGC) A; // a is uncollectable. | |
51 | ||
52 | Both uncollectable and collectable objects can be explicitly deleted | |
53 | with "delete", which invokes an object's destructors and frees its | |
54 | storage immediately. | |
55 | ||
56 | A collectable object may have a clean-up function, which will be | |
57 | invoked when the collector discovers the object to be inaccessible. | |
58 | An object derived from "gc_cleanup" or containing a member derived | |
59 | from "gc_cleanup" has a default clean-up function that invokes the | |
60 | object's destructors. Explicit clean-up functions may be specified as | |
61 | an additional placement argument: | |
62 | ||
63 | A* a = ::new (GC, MyCleanup) A; | |
64 | ||
65 | An object is considered "accessible" by the collector if it can be | |
66 | reached by a path of pointers from static variables, automatic | |
67 | variables of active functions, or from some object with clean-up | |
68 | enabled; pointers from an object to itself are ignored. | |
69 | ||
70 | Thus, if objects A and B both have clean-up functions, and A points at | |
71 | B, B is considered accessible. After A's clean-up is invoked and its | |
72 | storage released, B will then become inaccessible and will have its | |
73 | clean-up invoked. If A points at B and B points to A, forming a | |
74 | cycle, then that's considered a storage leak, and neither will be | |
75 | collectable. See the interface gc.h for low-level facilities for | |
76 | handling such cycles of objects with clean-up. | |
77 | ||
78 | The collector cannot guarrantee that it will find all inaccessible | |
79 | objects. In practice, it finds almost all of them. | |
80 | ||
81 | ||
82 | Cautions: | |
83 | ||
84 | 1. Be sure the collector has been augmented with "make c++". | |
85 | ||
86 | 2. If your compiler supports the new "operator new[]" syntax, then | |
87 | add -DOPERATOR_NEW_ARRAY to the Makefile. | |
88 | ||
89 | If your compiler doesn't support "operator new[]", beware that an | |
90 | array of type T, where T is derived from "gc", may or may not be | |
91 | allocated as a collectable object (it depends on the compiler). Use | |
92 | the explicit GC placement to make the array collectable. For example: | |
93 | ||
94 | class A: public gc {...}; | |
95 | A* a1 = new A[ 10 ]; // collectable or uncollectable? | |
96 | A* a2 = new (GC) A[ 10 ]; // collectable | |
97 | ||
98 | 3. The destructors of collectable arrays of objects derived from | |
99 | "gc_cleanup" will not be invoked properly. For example: | |
100 | ||
101 | class A: public gc_cleanup {...}; | |
102 | A* a = new (GC) A[ 10 ]; // destructors not invoked correctly | |
103 | ||
104 | Typically, only the destructor for the first element of the array will | |
105 | be invoked when the array is garbage-collected. To get all the | |
106 | destructors of any array executed, you must supply an explicit | |
107 | clean-up function: | |
108 | ||
109 | A* a = new (GC, MyCleanUp) A[ 10 ]; | |
110 | ||
111 | (Implementing clean-up of arrays correctly, portably, and in a way | |
112 | that preserves the correct exception semantics requires a language | |
113 | extension, e.g. the "gc" keyword.) | |
114 | ||
115 | 4. Compiler bugs: | |
116 | ||
117 | * Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the | |
118 | destructors of classes derived from gc_cleanup won't be invoked. | |
119 | You'll have to explicitly register a clean-up function with | |
120 | new-placement syntax. | |
121 | ||
122 | * Evidently cfront 3.0 does not allow destructors to be explicitly | |
123 | invoked using the ANSI-conforming syntax t->~T(). If you're using | |
124 | cfront 3.0, you'll have to comment out the class gc_cleanup, which | |
125 | uses explicit invocation. | |
126 | ||
127 | ****************************************************************************/ | |
128 | ||
129 | #include "gc.h" | |
130 | ||
131 | #ifndef THINK_CPLUS | |
132 | #define _cdecl | |
133 | #endif | |
134 | ||
135 | #if ! defined( OPERATOR_NEW_ARRAY ) \ | |
20bbd3cd TT |
136 | && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6) \ |
137 | || __WATCOMC__ >= 1050) | |
73ffefd0 TT |
138 | # define OPERATOR_NEW_ARRAY |
139 | #endif | |
140 | ||
141 | enum GCPlacement {GC, NoGC, PointerFreeGC}; | |
142 | ||
143 | class gc {public: | |
144 | inline void* operator new( size_t size ); | |
145 | inline void* operator new( size_t size, GCPlacement gcp ); | |
146 | inline void operator delete( void* obj ); | |
147 | ||
148 | #ifdef OPERATOR_NEW_ARRAY | |
149 | inline void* operator new[]( size_t size ); | |
150 | inline void* operator new[]( size_t size, GCPlacement gcp ); | |
151 | inline void operator delete[]( void* obj ); | |
152 | #endif /* OPERATOR_NEW_ARRAY */ | |
153 | }; | |
154 | /* | |
155 | Instances of classes derived from "gc" will be allocated in the | |
156 | collected heap by default, unless an explicit NoGC placement is | |
157 | specified. */ | |
158 | ||
159 | class gc_cleanup: virtual public gc {public: | |
160 | inline gc_cleanup(); | |
161 | inline virtual ~gc_cleanup(); | |
162 | private: | |
163 | inline static void _cdecl cleanup( void* obj, void* clientData );}; | |
164 | /* | |
165 | Instances of classes derived from "gc_cleanup" will be allocated | |
166 | in the collected heap by default. When the collector discovers an | |
167 | inaccessible object derived from "gc_cleanup" or containing a | |
168 | member derived from "gc_cleanup", its destructors will be | |
169 | invoked. */ | |
170 | ||
171 | extern "C" {typedef void (*GCCleanUpFunc)( void* obj, void* clientData );} | |
172 | ||
173 | inline void* operator new( | |
174 | size_t size, | |
175 | GCPlacement gcp, | |
176 | GCCleanUpFunc cleanup = 0, | |
177 | void* clientData = 0 ); | |
178 | /* | |
179 | Allocates a collectable or uncollected object, according to the | |
180 | value of "gcp". | |
181 | ||
182 | For collectable objects, if "cleanup" is non-null, then when the | |
183 | allocated object "obj" becomes inaccessible, the collector will | |
184 | invoke the function "cleanup( obj, clientData )" but will not | |
185 | invoke the object's destructors. It is an error to explicitly | |
186 | delete an object allocated with a non-null "cleanup". | |
187 | ||
188 | It is an error to specify a non-null "cleanup" with NoGC or for | |
189 | classes derived from "gc_cleanup" or containing members derived | |
190 | from "gc_cleanup". */ | |
191 | ||
192 | #ifdef OPERATOR_NEW_ARRAY | |
193 | ||
194 | inline void* operator new[]( | |
195 | size_t size, | |
196 | GCPlacement gcp, | |
197 | GCCleanUpFunc cleanup = 0, | |
198 | void* clientData = 0 ); | |
199 | /* | |
200 | The operator new for arrays, identical to the above. */ | |
201 | ||
202 | #endif /* OPERATOR_NEW_ARRAY */ | |
203 | ||
204 | /**************************************************************************** | |
205 | ||
206 | Inline implementation | |
207 | ||
208 | ****************************************************************************/ | |
209 | ||
210 | inline void* gc::operator new( size_t size ) { | |
211 | return GC_MALLOC( size );} | |
212 | ||
213 | inline void* gc::operator new( size_t size, GCPlacement gcp ) { | |
214 | if (gcp == GC) | |
215 | return GC_MALLOC( size ); | |
20bbd3cd TT |
216 | else if (gcp == PointerFreeGC) |
217 | return GC_MALLOC_ATOMIC( size ); | |
73ffefd0 TT |
218 | else |
219 | return GC_MALLOC_UNCOLLECTABLE( size );} | |
220 | ||
221 | inline void gc::operator delete( void* obj ) { | |
222 | GC_FREE( obj );} | |
223 | ||
224 | ||
225 | #ifdef OPERATOR_NEW_ARRAY | |
226 | ||
227 | inline void* gc::operator new[]( size_t size ) { | |
228 | return gc::operator new( size );} | |
229 | ||
230 | inline void* gc::operator new[]( size_t size, GCPlacement gcp ) { | |
231 | return gc::operator new( size, gcp );} | |
232 | ||
233 | inline void gc::operator delete[]( void* obj ) { | |
234 | gc::operator delete( obj );} | |
235 | ||
236 | #endif /* OPERATOR_NEW_ARRAY */ | |
237 | ||
238 | ||
239 | inline gc_cleanup::~gc_cleanup() { | |
20bbd3cd | 240 | GC_REGISTER_FINALIZER_IGNORE_SELF( GC_base(this), 0, 0, 0, 0 );} |
73ffefd0 TT |
241 | |
242 | inline void gc_cleanup::cleanup( void* obj, void* displ ) { | |
243 | ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();} | |
244 | ||
245 | inline gc_cleanup::gc_cleanup() { | |
246 | GC_finalization_proc oldProc; | |
247 | void* oldData; | |
248 | void* base = GC_base( (void *) this ); | |
249 | if (0 == base) return; | |
250 | GC_REGISTER_FINALIZER_IGNORE_SELF( | |
251 | base, cleanup, (void*) ((char*) this - (char*) base), | |
252 | &oldProc, &oldData ); | |
253 | if (0 != oldProc) { | |
254 | GC_REGISTER_FINALIZER_IGNORE_SELF( base, oldProc, oldData, 0, 0 );}} | |
255 | ||
256 | inline void* operator new( | |
257 | size_t size, | |
258 | GCPlacement gcp, | |
259 | GCCleanUpFunc cleanup, | |
260 | void* clientData ) | |
261 | { | |
262 | void* obj; | |
263 | ||
264 | if (gcp == GC) { | |
265 | obj = GC_MALLOC( size ); | |
266 | if (cleanup != 0) | |
267 | GC_REGISTER_FINALIZER_IGNORE_SELF( | |
268 | obj, cleanup, clientData, 0, 0 );} | |
269 | else if (gcp == PointerFreeGC) { | |
270 | obj = GC_MALLOC_ATOMIC( size );} | |
271 | else { | |
272 | obj = GC_MALLOC_UNCOLLECTABLE( size );}; | |
273 | return obj;} | |
274 | ||
275 | ||
276 | #ifdef OPERATOR_NEW_ARRAY | |
277 | ||
278 | inline void* operator new[]( | |
279 | size_t size, | |
280 | GCPlacement gcp, | |
281 | GCCleanUpFunc cleanup, | |
282 | void* clientData ) | |
283 | { | |
284 | return ::operator new( size, gcp, cleanup, clientData );} | |
285 | ||
286 | #endif /* OPERATOR_NEW_ARRAY */ | |
287 | ||
288 | ||
289 | #endif /* GC_CPP_H */ | |
290 |