*/
#ifndef GC_ALLOCATOR_H
-
#define GC_ALLOCATOR_H
#include "gc.h"
-#include <new> // for placement new
+#include <new> // for placement new and bad_alloc
#ifndef GC_ATTR_EXPLICIT
# if (__cplusplus >= 201103L) || defined(CPPCHECK)
# endif
#endif
+#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
+# define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
+#else
+# define GC_ALLOCATOR_THROW_OR_ABORT() throw std::bad_alloc()
+#endif
+
/* First some helpers to allow us to dispatch on whether or not a type
* is known to be pointer-free.
* These are private, except that the client may invoke the
// pointer-free object.
template <class GC_Tp>
inline void * GC_selective_alloc(size_t n, GC_Tp, bool ignore_off_page) {
- return ignore_off_page?GC_MALLOC_IGNORE_OFF_PAGE(n):GC_MALLOC(n);
+ void *obj = ignore_off_page ? GC_MALLOC_IGNORE_OFF_PAGE(n) : GC_MALLOC(n);
+ if (0 == obj)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return obj;
}
#if !defined(__WATCOMC__)
template <>
inline void * GC_selective_alloc<GC_true_type>(size_t n, GC_true_type,
bool ignore_off_page) {
- return ignore_off_page? GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(n)
- : GC_MALLOC_ATOMIC(n);
+ void * obj = ignore_off_page ? GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(n)
+ : GC_MALLOC_ATOMIC(n);
+ if (0 == obj)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return obj;
}
#endif
// GC_n is permitted to be 0. The C++ standard says nothing about what
// the return value is when GC_n == 0.
GC_Tp* allocate(size_type GC_n, const void* = 0) {
- return static_cast<GC_Tp*>(GC_MALLOC_UNCOLLECTABLE(GC_n * sizeof(GC_Tp)));
+ void * obj = GC_MALLOC_UNCOLLECTABLE(GC_n * sizeof(GC_Tp));
+ if (0 == obj)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return static_cast<GC_Tp*>(obj);
}
// __p is not permitted to be a null pointer.
#define GC_generic_malloc_words_small(lw, k) \
GC_generic_malloc((lw) * sizeof(GC_word), k)
+#define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
+
// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
// AUNCOLLECTABLE in gc_priv.h.
void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
{
void * op = GC_generic_malloc_words_small(nwords, kind);
- if (!op) return 0;
+ if (0 == op)
+ GC_ALLOCATOR_THROW_OR_ABORT();
GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd;
GC_non_gc_bytes +=
void ** flh;
void * op;
- if (n > GC_max_fast_bytes) return GC_malloc(n);
+ if (n > GC_max_fast_bytes) {
+ op = GC_malloc(n);
+ if (0 == op)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return op;
+ }
flh = &GC_objfreelist_ptr[nwords];
op = *flh;
if (0 == op) {
void ** flh;
void * op;
- if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
+ if (n > GC_max_fast_bytes) {
+ op = GC_malloc_atomic(n);
+ if (0 == op)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return op;
+ }
flh = &GC_aobjfreelist_ptr[nwords];
op = *flh;
if (0 == op) {
void ** flh;
void * op;
- if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
+ if (n > GC_max_fast_bytes) {
+ op = GC_malloc_uncollectable(n);
+ if (0 == op)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return op;
+ }
flh = &GC_uobjfreelist_ptr[nwords];
op = *flh;
if (0 == op) {
void ** flh;
void * op;
- if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
+ if (n > GC_max_fast_bytes) {
+ op = GC_malloc_atomic_uncollectable(n);
+ if (0 == op)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return op;
+ }
flh = &GC_auobjfreelist_ptr[nwords];
op = *flh;
if (0 == op) {
template < int dummy >
class gc_alloc_template {
public:
- static void * allocate(size_t n) { return GC_malloc(n); }
- static void * ptr_free_allocate(size_t n)
- { return GC_malloc_atomic(n); }
+ static void * allocate(size_t n) {
+ void * op = GC_malloc(n);
+ if (0 == op)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return op;
+ }
+ static void * ptr_free_allocate(size_t n) {
+ void * op = GC_malloc_atomic(n);
+ if (0 == op)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return op;
+ }
static void deallocate(void *, size_t) { }
static void ptr_free_deallocate(void *, size_t) { }
};
template < int dummy >
class traceable_alloc_template {
public:
- static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
- static void * ptr_free_allocate(size_t n)
- { return GC_malloc_atomic_uncollectable(n); }
+ static void * allocate(size_t n) {
+ void * op = GC_malloc_uncollectable(n);
+ if (0 == op)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return op;
+ }
+ static void * ptr_free_allocate(size_t n) {
+ void * op = GC_malloc_atomic_uncollectable(n);
+ if (0 == op)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return op;
+ }
static void deallocate(void *p, size_t) { GC_free(p); }
static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
};
class simple_alloc<T, alloc> { \
public: \
static T *allocate(size_t n) \
- { return 0 == n? 0 : \
- reinterpret_cast<T*>(alloc::ptr_free_allocate(n * sizeof(T))); } \
+ { reinterpret_cast<T*>(alloc::ptr_free_allocate(0 == n ? 1 \
+ : n * sizeof(T))); } \
static T *allocate(void) \
{ return reinterpret_cast<T*>(alloc::ptr_free_allocate(sizeof(T))); } \
static void deallocate(T *p, size_t n) \
- { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof(T)); } \
+ { alloc::ptr_free_deallocate(p, 0 == n ? 1 : n * sizeof(T)); } \
static void deallocate(T *p) \
{ alloc::ptr_free_deallocate(p, sizeof(T)); } \
};