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