gc_cpp.h raw
1 /*
2 * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
3 *
4 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
6 *
7 * Permission is hereby granted to use or copy this program for any
8 * purpose, provided the above notices are retained on all copies.
9 * Permission to modify the code and to distribute modified code is
10 * granted, provided the above notices are retained, and a notice that
11 * the code was modified is included with the above copyright notice.
12 */
13
14 #ifndef GC_CPP_H
15 #define GC_CPP_H
16
17 /*
18 C++ Interface to the Boehm Collector
19
20 John R. Ellis and Jesse Hull
21
22 This interface provides access to the Boehm collector.
23 It provides basic facilities similar to those described in
24 "Safe, Efficient Garbage Collection for C++", by John R. Ellis and
25 David L. Detlefs.
26
27 All heap-allocated objects are either "collectible" or
28 "uncollectible". Programs must explicitly delete uncollectible
29 objects, whereas the garbage collector will automatically delete
30 collectible objects when it discovers them to be inaccessible.
31 Collectible objects may freely point at uncollectible objects and vice
32 versa.
33
34 Objects allocated with the built-in `::operator new` are uncollectible.
35
36 Objects derived from class `gc` are collectible. E.g.:
37
38 ```
39 class A: public gc {...};
40 A *a = new A; // a is collectible
41 ```
42
43 Collectible instances of non-class types can be allocated using `GC`
44 (or `UseGC`) placement:
45
46 ```
47 typedef int A[10];
48 A *a = new (GC) A;
49 ```
50
51 Uncollectible instances of classes derived from `gc` can be allocated
52 using `NoGC` placement:
53
54 ```
55 class A: public gc {...};
56 A *a = new (NoGC) A; // a is uncollectible
57 ```
58
59 The `new(PointerFreeGC)` syntax allows the allocation of collectible
60 objects that are not scanned by the collector. This useful if you
61 are allocating compressed data, bitmaps, or network packets. (In
62 the latter case, it may remove danger of unfriendly network packets
63 intentionally containing values that cause spurious memory retention.)
64
65 Both uncollectible and collectible objects can be explicitly deleted
66 with `operator delete`, which invokes an object's destructors and frees
67 its storage immediately.
68
69 A collectible object may have a cleanup function, which will be
70 invoked when the collector discovers the object to be inaccessible.
71 An object derived from `gc_cleanup` or containing a member derived
72 from `gc_cleanup` has a default cleanup function that invokes the
73 object's destructors. Explicit cleanup functions may be specified as
74 an additional placement argument:
75
76 ```
77 A *a = ::new (GC, MyCleanup) A;
78 ```
79
80 An object is considered "accessible" by the collector if it can be
81 reached by a path of pointers from `static` variables, automatic
82 variables of active functions, or from some object with cleanup
83 enabled; pointers from an object to itself are ignored.
84
85 Thus, if objects A and B both have cleanup functions, and A points at
86 B, B is considered accessible. After A's cleanup is invoked and its
87 storage released, B will then become inaccessible and will have its
88 cleanup invoked. If A points at B and B points to A, forming a
89 cycle, then that is considered a storage leak, and neither will be
90 collectible. See the interface in `gc.h` file for low-level facilities
91 for handling such cycles of objects with cleanup.
92
93 The collector cannot guarantee that it will find all inaccessible
94 objects. In practice, it finds almost all of them.
95
96 Cautions:
97
98 1. Be sure the collector is compiled with the C++ support
99 (e.g. `--enable-cplusplus` option is passed to `configure`).
100
101 2. If the compiler does not support `operator new[]`, beware that an
102 array of type `T`, where `T` is derived from `gc`, may or may not be
103 allocated as a collectible object (it depends on the compiler). Use
104 the explicit GC placement to make the array collectible. E.g.:
105
106 ```
107 class A: public gc {...};
108 A *a1 = new A[10]; // collectible or uncollectible?
109 A *a2 = new (GC) A[10]; // collectible
110 ```
111
112 3. The destructors of collectible arrays of objects derived from
113 `gc_cleanup` will not be invoked properly. E.g.:
114
115 ```
116 class A: public gc_cleanup {...};
117 A *a = new (GC) A[10]; // destructors not invoked correctly
118 ```
119 Typically, only the destructor for the first element of the array will
120 be invoked when the array is garbage-collected. To get all the
121 destructors of any array executed, you must supply an explicit
122 cleanup function:
123
124 ```
125 A *a = new (GC, MyCleanUp) A[10];
126 ```
127 (Implementing cleanup of arrays correctly, portably, and in a way
128 that preserves the correct exception semantics, requires a language
129 extension, e.g. the `gc` keyword.)
130
131 4. GC name conflicts: Many other systems seem to use the identifier `GC`
132 as an abbreviation for "Graphics Context". Thus, `GC` placement has
133 been replaced by `UseGC`. `GC` is an alias for `UseGC`, unless
134 `GC_NAME_CONFLICT` macro is defined.
135 */
136
137 #include "gc.h"
138
139 #ifdef GC_INCLUDE_NEW
140 # include <new> // for `std`, `bad_alloc`
141 #endif
142
143 #if defined(GC_INCLUDE_NEW) && (__cplusplus >= 201103L)
144 # define GC_PTRDIFF_T std::ptrdiff_t
145 # define GC_SIZE_T std::size_t
146 #else
147 # define GC_PTRDIFF_T ptrdiff_t
148 # define GC_SIZE_T size_t
149 #endif
150
151 #ifdef GC_NAMESPACE
152 # define GC_NS_QUALIFY(T) boehmgc::T
153 #else
154 # define GC_NS_QUALIFY(T) T
155 #endif
156
157 #define GC_cdecl GC_CALLBACK
158
159 #if !defined(GC_NO_OPERATOR_NEW_ARRAY) \
160 && !defined(_ENABLE_ARRAYNEW) /*< Digital Mars */ \
161 && (defined(__BORLANDC__) && (__BORLANDC__ < 0x450) \
162 || (defined(__GNUC__) && !GC_GNUC_PREREQ(2, 6)) \
163 || (defined(_MSC_VER) && _MSC_VER <= 1020) \
164 || (defined(__WATCOMC__) && __WATCOMC__ < 1050))
165 # define GC_NO_OPERATOR_NEW_ARRAY
166 #endif
167
168 #if !defined(GC_NO_OPERATOR_NEW_ARRAY) && !defined(GC_OPERATOR_NEW_ARRAY)
169 # define GC_OPERATOR_NEW_ARRAY
170 #endif
171
172 #if !defined(GC_NO_INLINE_STD_NEW) && !defined(GC_INLINE_STD_NEW) \
173 && (defined(_MSC_VER) || defined(__DMC__) \
174 || ((defined(__BORLANDC__) || defined(__CYGWIN__) \
175 || defined(__CYGWIN32__) || defined(__MINGW32__) \
176 || defined(__WATCOMC__)) \
177 && !defined(GC_BUILD) && !defined(GC_NOT_DLL)))
178 // Inlining done to avoid mix up of `new` and `delete` operators by VC++ 9
179 // (due to arbitrary ordering during linking).
180 # define GC_INLINE_STD_NEW
181 #endif
182
183 #if (!defined(__BORLANDC__) || __BORLANDC__ > 0x0620) && !defined(__sgi) \
184 && !defined(__WATCOMC__) && (!defined(_MSC_VER) || _MSC_VER > 1020)
185 # define GC_PLACEMENT_DELETE
186 #endif
187
188 #if !defined(GC_OPERATOR_SIZED_DELETE) \
189 && !defined(GC_NO_OPERATOR_SIZED_DELETE) \
190 && (__cplusplus >= 201402L || _MSVC_LANG >= 201402L) // C++14
191 # define GC_OPERATOR_SIZED_DELETE
192 #endif
193
194 #if !defined(GC_OPERATOR_NEW_NOTHROW) && !defined(GC_NO_OPERATOR_NEW_NOTHROW) \
195 && ((defined(GC_INCLUDE_NEW) \
196 && (__cplusplus >= 201103L || _MSVC_LANG >= 201103L)) \
197 || defined(__NOTHROW_T_DEFINED))
198 // Note: this might require defining `GC_INCLUDE_NEW` macro by client
199 // before include `gc_cpp.h` file (on Windows).
200 # define GC_OPERATOR_NEW_NOTHROW
201 #endif
202
203 #if !defined(GC_NEW_DELETE_THROW_NOT_NEEDED) \
204 && !defined(GC_NEW_DELETE_NEED_THROW) && GC_GNUC_PREREQ(4, 2) \
205 && (__cplusplus < 201103L || defined(__clang__))
206 # define GC_NEW_DELETE_NEED_THROW
207 #endif
208
209 #ifndef GC_NEW_DELETE_NEED_THROW
210 # define GC_DECL_NEW_THROW /*< empty */
211 #elif __cplusplus >= 201703L || _MSVC_LANG >= 201703L
212 // The "dynamic exception" syntax had been deprecated in C++11
213 // and was removed in C++17.
214 # define GC_DECL_NEW_THROW noexcept(false)
215 #elif defined(GC_INCLUDE_NEW)
216 # define GC_DECL_NEW_THROW throw(std::bad_alloc)
217 #else
218 # define GC_DECL_NEW_THROW /*< empty (as `bad_alloc` might be undeclared) */
219 #endif
220
221 #if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
222 # define GC_OP_NEW_OOM_CHECK(obj) \
223 do { \
224 if (!(obj)) \
225 GC_abort_on_oom(); \
226 } while (0)
227 #elif defined(GC_INCLUDE_NEW)
228 # define GC_OP_NEW_OOM_CHECK(obj) \
229 if (obj) { \
230 } else \
231 throw std::bad_alloc()
232 #else
233 // The platform `new` header file is not included, so `bad_alloc` cannot
234 // be thrown directly.
235 GC_API GC_OOM_ABORT_THROW_ATTRIBUTE void GC_CALL GC_throw_bad_alloc();
236 # define GC_OP_NEW_OOM_CHECK(obj) \
237 if (obj) { \
238 } else \
239 GC_throw_bad_alloc()
240 #endif // !GC_NEW_ABORTS_ON_OOM && !GC_INCLUDE_NEW
241
242 #ifdef GC_NAMESPACE
243 namespace boehmgc
244 {
245 #endif
246
247 enum GCPlacement {
248 UseGC,
249 #ifndef GC_NAME_CONFLICT
250 GC = UseGC,
251 #endif
252 NoGC,
253 PointerFreeGC
254 #ifdef GC_ATOMIC_UNCOLLECTABLE
255 ,
256 PointerFreeNoGC
257 #endif
258 };
259
260 // Instances of classes derived from `gc` will be allocated in the collected
261 // heap by default, unless an explicit `NoGC` placement is specified.
262 class gc
263 {
264 public:
265 inline void *operator new(GC_SIZE_T);
266 inline void *operator new(GC_SIZE_T, GCPlacement);
267
268 // Must be redefined here, since the other overloadings hide
269 // the global definition.
270 inline void *operator new(GC_SIZE_T, void *) GC_NOEXCEPT;
271
272 inline void operator delete(void *) GC_NOEXCEPT;
273 #ifdef GC_OPERATOR_SIZED_DELETE
274 inline void operator delete(void *, GC_SIZE_T) GC_NOEXCEPT;
275 #endif
276
277 #ifdef GC_PLACEMENT_DELETE
278 // Called if construction fails.
279 inline void operator delete(void *, GCPlacement) GC_NOEXCEPT;
280
281 inline void operator delete(void *, void *) GC_NOEXCEPT;
282 #endif // GC_PLACEMENT_DELETE
283
284 #ifdef GC_OPERATOR_NEW_ARRAY
285 inline void *operator new[](GC_SIZE_T);
286 inline void *operator new[](GC_SIZE_T, GCPlacement);
287 inline void *operator new[](GC_SIZE_T, void *) GC_NOEXCEPT;
288 inline void operator delete[](void *) GC_NOEXCEPT;
289 # ifdef GC_OPERATOR_SIZED_DELETE
290 inline void operator delete[](void *, GC_SIZE_T) GC_NOEXCEPT;
291 # endif
292 # ifdef GC_PLACEMENT_DELETE
293 inline void operator delete[](void *, GCPlacement) GC_NOEXCEPT;
294 inline void operator delete[](void *, void *) GC_NOEXCEPT;
295 # endif
296 #endif
297 };
298
299 // Instances of classes derived from gc_cleanup will be allocated in the
300 // collected heap by default. When the collector discovers an inaccessible
301 // object derived from `gc_cleanup` or containing a member derived from
302 // `gc_cleanup`, its destructors will be invoked.
303 class gc_cleanup : virtual public gc
304 {
305 public:
306 inline gc_cleanup();
307 inline virtual ~gc_cleanup();
308
309 private:
310 inline static void GC_cdecl cleanup(void *obj, void *clientData);
311 };
312
313 extern "C" {
314 typedef void(GC_CALLBACK *GCCleanUpFunc)(void *obj, void *clientData);
315 }
316
317 #ifdef GC_NAMESPACE
318 }
319 #endif
320
321 #ifdef _MSC_VER
322 // Disable warning that "no matching operator delete found; memory will
323 // not be freed if initialization throws an exception"
324 # pragma warning(disable : 4291)
325 // TODO: "non-member operator new or delete may not be declared inline"
326 // warning is disabled for now.
327 # pragma warning(disable : 4595)
328 #endif
329
330 // Allocates a collectible or uncollectible object, according to the
331 // value of `gcp`.
332 // For collectible objects, if `cleanup` is non-null, then when the
333 // allocated object `obj` becomes inaccessible, the collector will
334 // invoke `cleanup(obj, clientData)` but will not invoke the object's
335 // destructors. It is an error to explicitly `delete` an object
336 // allocated with a non-null `cleanup`.
337 // It is an error to specify a non-null `cleanup` with `NoGC` or for
338 // classes derived from `gc_cleanup` or containing members derived
339 // from `gc_cleanup`.
340 inline void *operator new(GC_SIZE_T, GC_NS_QUALIFY(GCPlacement) /* `gcp` */,
341 GC_NS_QUALIFY(GCCleanUpFunc) = 0 /* `cleanup` */,
342 void * /* `clientData` */ = 0);
343
344 #ifdef GC_PLACEMENT_DELETE
345 inline void operator delete(void *, GC_NS_QUALIFY(GCPlacement),
346 GC_NS_QUALIFY(GCCleanUpFunc), void *) GC_NOEXCEPT;
347 #endif
348
349 #ifdef GC_INLINE_STD_NEW
350
351 # ifdef GC_OPERATOR_NEW_ARRAY
352 inline void *
353 operator new[](GC_SIZE_T size) GC_DECL_NEW_THROW
354 {
355 void *obj = GC_MALLOC_UNCOLLECTABLE(size);
356 GC_OP_NEW_OOM_CHECK(obj);
357 return obj;
358 }
359
360 inline void
361 operator delete[](void *obj) GC_NOEXCEPT
362 {
363 GC_FREE(obj);
364 }
365
366 # ifdef GC_OPERATOR_NEW_NOTHROW
367 inline /* `GC_ATTR_MALLOC` */ void *
368 operator new[](GC_SIZE_T size, const std::nothrow_t &) GC_NOEXCEPT
369 {
370 return GC_MALLOC_UNCOLLECTABLE(size);
371 }
372
373 inline void
374 operator delete[](void *obj, const std::nothrow_t &) GC_NOEXCEPT
375 {
376 GC_FREE(obj);
377 }
378 # endif
379 # endif // GC_OPERATOR_NEW_ARRAY
380
381 inline void *
382 operator new(GC_SIZE_T size) GC_DECL_NEW_THROW
383 {
384 void *obj = GC_MALLOC_UNCOLLECTABLE(size);
385 GC_OP_NEW_OOM_CHECK(obj);
386 return obj;
387 }
388
389 inline void
390 operator delete(void *obj) GC_NOEXCEPT
391 {
392 GC_FREE(obj);
393 }
394
395 # ifdef GC_OPERATOR_NEW_NOTHROW
396 inline /* `GC_ATTR_MALLOC` */ void *
397 operator new(GC_SIZE_T size, const std::nothrow_t &) GC_NOEXCEPT
398 {
399 return GC_MALLOC_UNCOLLECTABLE(size);
400 }
401
402 inline void
403 operator delete(void *obj, const std::nothrow_t &) GC_NOEXCEPT
404 {
405 GC_FREE(obj);
406 }
407 # endif // GC_OPERATOR_NEW_NOTHROW
408
409 # ifdef GC_OPERATOR_SIZED_DELETE
410 inline void
411 operator delete(void *obj, GC_SIZE_T) GC_NOEXCEPT
412 {
413 GC_FREE(obj);
414 }
415
416 # ifdef GC_OPERATOR_NEW_ARRAY
417 inline void
418 operator delete[](void *obj, GC_SIZE_T) GC_NOEXCEPT
419 {
420 GC_FREE(obj);
421 }
422 # endif
423 # endif // GC_OPERATOR_SIZED_DELETE
424
425 # ifdef _MSC_VER
426 // This new operator is used by VC++ in case of Debug builds.
427 inline void *
428 operator new(GC_SIZE_T size, int /* `nBlockUse` */, const char *szFileName,
429 int nLine)
430 {
431 # ifdef GC_DEBUG
432 void *obj = GC_debug_malloc_uncollectable(size, szFileName, nLine);
433 # else
434 void *obj = GC_MALLOC_UNCOLLECTABLE(size);
435 (void)szFileName;
436 (void)nLine;
437 # endif
438 GC_OP_NEW_OOM_CHECK(obj);
439 return obj;
440 }
441
442 # ifdef GC_OPERATOR_NEW_ARRAY
443 // This new operator is used by VC++ 7+ in Debug builds.
444 inline void *
445 operator new[](GC_SIZE_T size, int nBlockUse, const char *szFileName,
446 int nLine)
447 {
448 return operator new(size, nBlockUse, szFileName, nLine);
449 }
450 # endif
451 # endif // _MSC_VER
452
453 #elif defined(GC_NO_INLINE_STD_NEW) && defined(_MSC_VER)
454
455 // The following ensures that the system default `operator new[]` does not
456 // get undefined, which is what seems to happen on VC++ 6 for some reason
457 // if we define a multi-argument `operator new[]`.
458 // There seems to be no way to redirect new in this environment without
459 // including this everywhere.
460 # ifdef GC_OPERATOR_NEW_ARRAY
461 void *operator new[](GC_SIZE_T) GC_DECL_NEW_THROW;
462 void operator delete[](void *) GC_NOEXCEPT;
463 # ifdef GC_OPERATOR_NEW_NOTHROW
464 /* `GC_ATTR_MALLOC` */ void *
465 operator new[](GC_SIZE_T, const std::nothrow_t &) GC_NOEXCEPT;
466 void operator delete[](void *, const std::nothrow_t &) GC_NOEXCEPT;
467 # endif
468 # ifdef GC_OPERATOR_SIZED_DELETE
469 void operator delete[](void *, GC_SIZE_T) GC_NOEXCEPT;
470 # endif
471
472 void *operator new[](GC_SIZE_T, int /* `nBlockUse` */,
473 const char * /* `szFileName` */, int /* `nLine` */);
474 # endif // GC_OPERATOR_NEW_ARRAY
475
476 void *operator new(GC_SIZE_T) GC_DECL_NEW_THROW;
477 void operator delete(void *) GC_NOEXCEPT;
478 # ifdef GC_OPERATOR_NEW_NOTHROW
479 /* GC_ATTR_MALLOC */ void *operator new(GC_SIZE_T,
480 const std::nothrow_t &) GC_NOEXCEPT;
481 void operator delete(void *, const std::nothrow_t &) GC_NOEXCEPT;
482 # endif
483 # ifdef GC_OPERATOR_SIZED_DELETE
484 void operator delete(void *, GC_SIZE_T) GC_NOEXCEPT;
485 # endif
486
487 void *operator new(GC_SIZE_T, int /* `nBlockUse` */,
488 const char * /* `szFileName` */, int /* `nLine` */);
489
490 #endif // GC_NO_INLINE_STD_NEW && _MSC_VER
491
492 #ifdef GC_OPERATOR_NEW_ARRAY
493 // The `operator new` for arrays, identical to the above.
494 inline void *operator new[](GC_SIZE_T, GC_NS_QUALIFY(GCPlacement),
495 GC_NS_QUALIFY(GCCleanUpFunc) = 0,
496 void * /* `clientData` */ = 0);
497 #endif // GC_OPERATOR_NEW_ARRAY
498
499 // Inline implementation.
500
501 #ifdef GC_NAMESPACE
502 namespace boehmgc
503 {
504 #endif
505
506 inline void *
507 gc::operator new(GC_SIZE_T size)
508 {
509 void *obj = GC_MALLOC(size);
510 GC_OP_NEW_OOM_CHECK(obj);
511 return obj;
512 }
513
514 inline void *
515 gc::operator new(GC_SIZE_T size, GCPlacement gcp)
516 {
517 void *obj;
518 switch (gcp) {
519 case UseGC:
520 obj = GC_MALLOC(size);
521 break;
522 case PointerFreeGC:
523 obj = GC_MALLOC_ATOMIC(size);
524 break;
525 #ifdef GC_ATOMIC_UNCOLLECTABLE
526 case PointerFreeNoGC:
527 obj = GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
528 break;
529 #endif
530 case NoGC:
531 default:
532 obj = GC_MALLOC_UNCOLLECTABLE(size);
533 }
534 GC_OP_NEW_OOM_CHECK(obj);
535 return obj;
536 }
537
538 inline void *
539 gc::operator new(GC_SIZE_T, void *p) GC_NOEXCEPT
540 {
541 return p;
542 }
543
544 inline void
545 gc::operator delete(void *obj) GC_NOEXCEPT
546 {
547 GC_FREE(obj);
548 }
549
550 #ifdef GC_OPERATOR_SIZED_DELETE
551 inline void
552 gc::operator delete(void *obj, GC_SIZE_T) GC_NOEXCEPT
553 {
554 GC_FREE(obj);
555 }
556 #endif
557
558 #ifdef GC_PLACEMENT_DELETE
559 inline void
560 gc::operator delete(void *, void *) GC_NOEXCEPT
561 {
562 }
563
564 inline void
565 gc::operator delete(void *obj, GCPlacement) GC_NOEXCEPT
566 {
567 GC_FREE(obj);
568 }
569 #endif // GC_PLACEMENT_DELETE
570
571 #ifdef GC_OPERATOR_NEW_ARRAY
572 inline void *
573 gc::operator new[](GC_SIZE_T size)
574 {
575 return gc::operator new(size);
576 }
577
578 inline void *
579 gc::operator new[](GC_SIZE_T size, GCPlacement gcp)
580 {
581 return gc::operator new(size, gcp);
582 }
583
584 inline void *
585 gc::operator new[](GC_SIZE_T, void *p) GC_NOEXCEPT
586 {
587 return p;
588 }
589
590 inline void
591 gc::operator delete[](void *obj) GC_NOEXCEPT
592 {
593 gc::operator delete(obj);
594 }
595
596 # ifdef GC_OPERATOR_SIZED_DELETE
597 inline void
598 gc::operator delete[](void *obj, GC_SIZE_T size) GC_NOEXCEPT
599 {
600 gc::operator delete(obj, size);
601 }
602 # endif
603
604 # ifdef GC_PLACEMENT_DELETE
605 inline void
606 gc::operator delete[](void *, void *) GC_NOEXCEPT
607 {
608 }
609
610 inline void
611 gc::operator delete[](void *p, GCPlacement) GC_NOEXCEPT
612 {
613 gc::operator delete(p);
614 }
615 # endif
616 #endif // GC_OPERATOR_NEW_ARRAY
617
618 inline gc_cleanup::~gc_cleanup()
619 {
620 #ifndef GC_NO_FINALIZATION
621 void *base = GC_base(this);
622 if (0 == base)
623 return; // Non-heap object.
624 GC_register_finalizer_ignore_self(base, 0, 0, 0, 0);
625 #endif
626 }
627
628 inline void GC_CALLBACK
629 gc_cleanup::cleanup(void *obj, void *displ)
630 {
631 reinterpret_cast<gc_cleanup *>(
632 reinterpret_cast<char *>(obj)
633 + static_cast<GC_PTRDIFF_T>(reinterpret_cast<GC_uintptr_t>(displ)))
634 ->~gc_cleanup();
635 }
636
637 inline gc_cleanup::gc_cleanup()
638 {
639 #ifndef GC_NO_FINALIZATION
640 GC_finalization_proc oldProc = 0;
641 void *oldData = 0; // to avoid "might be uninitialized" compiler warning
642 void *this_ptr = reinterpret_cast<void *>(this);
643 void *base = GC_base(this_ptr);
644 if (base != 0) {
645 // Do not call the debug variant, since this is a real base address.
646 GC_register_finalizer_ignore_self(
647 base, reinterpret_cast<GC_finalization_proc>(cleanup),
648 reinterpret_cast<void *>(
649 static_cast<GC_uintptr_t>(reinterpret_cast<char *>(this_ptr)
650 - reinterpret_cast<char *>(base))),
651 &oldProc, &oldData);
652 if (oldProc != 0) {
653 GC_register_finalizer_ignore_self(base, oldProc, oldData, 0, 0);
654 }
655 }
656 #elif defined(CPPCHECK)
657 (void)cleanup;
658 #endif
659 }
660
661 #ifdef GC_NAMESPACE
662 }
663 #endif
664
665 inline void *
666 operator new(GC_SIZE_T size, GC_NS_QUALIFY(GCPlacement) gcp,
667 GC_NS_QUALIFY(GCCleanUpFunc) cleanup, void *clientData)
668 {
669 void *obj;
670 switch (gcp) {
671 case GC_NS_QUALIFY(UseGC):
672 obj = GC_MALLOC(size);
673 #ifndef GC_NO_FINALIZATION
674 if (cleanup != 0 && obj != 0) {
675 GC_REGISTER_FINALIZER_IGNORE_SELF(obj, cleanup, clientData, 0, 0);
676 }
677 #else
678 (void)cleanup;
679 (void)clientData;
680 #endif
681 break;
682 case GC_NS_QUALIFY(PointerFreeGC):
683 obj = GC_MALLOC_ATOMIC(size);
684 break;
685 #ifdef GC_ATOMIC_UNCOLLECTABLE
686 case GC_NS_QUALIFY(PointerFreeNoGC):
687 obj = GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
688 break;
689 #endif
690 case GC_NS_QUALIFY(NoGC):
691 default:
692 obj = GC_MALLOC_UNCOLLECTABLE(size);
693 }
694 GC_OP_NEW_OOM_CHECK(obj);
695 return obj;
696 }
697
698 #ifdef GC_PLACEMENT_DELETE
699 inline void
700 operator delete(void *obj, GC_NS_QUALIFY(GCPlacement),
701 GC_NS_QUALIFY(GCCleanUpFunc),
702 void * /* `clientData` */) GC_NOEXCEPT
703 {
704 GC_FREE(obj);
705 }
706 #endif // GC_PLACEMENT_DELETE
707
708 #ifdef GC_OPERATOR_NEW_ARRAY
709 inline void *
710 operator new[](GC_SIZE_T size, GC_NS_QUALIFY(GCPlacement) gcp,
711 GC_NS_QUALIFY(GCCleanUpFunc) cleanup, void *clientData)
712 {
713 return ::operator new(size, gcp, cleanup, clientData);
714 }
715 #endif
716
717 #endif /* GC_CPP_H */
718