1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
#ifndef NEWDELETE_H
#define NEWDELETE_H 1
#define GC_REDIRECT_TO_LOCAL
// get declarations of outofmem and getmem
#include "../d/M2mem.h"
#include "../d/debug.h"
#include <M2/gc-include.h>
#include <gc/gc_allocator.h>
#include <vector>
#ifdef MEMDEBUG
#include <memdebug.h>
#include <M2mem.h>
#endif
/**
@brief a version of the STL vector, which allocates its backing memory with gc.
This should be used instead of std::vector<T> in the following instances:
(1) T contains (or is a pointer to) memory allocated with GC, and
(2a) The object containing the vector is in GC collected memory
that is, it is in a struct or class inheriting from our_new_delete, or gc_cleanup,
or
(2b) The vector is in local memory, and has not been allocated on the heap.
It is a (probably hard to detect) error if exactly (1) or (2a) holds.
In that case, redesign your class!
*/
#define VECTOR(T) std::vector<T, gc_allocator<T>>
// these replace all uses of the construction "new T[n]" (unless constructors
// have to be run!):
#define newarray(T, len) reinterpret_cast<T *>(getmem((len) * sizeof(T)))
#define newarray_clear(T, len) \
reinterpret_cast<T *>(getmem_clear((len) * sizeof(T)))
// this replaces all uses of the construction "new T":
#define newitem(T) reinterpret_cast<T *>(getmem(sizeof(T)))
#define newitem_clear(T) reinterpret_cast<T *>(getmem_clear(sizeof(T)))
// this replaces all uses of the construction "new T[n]", with T containing NO
// pointers
#define newarray_atomic(T, len) \
reinterpret_cast<T *>(getmem_atomic((len) * sizeof(T)))
#define newarray_atomic_clear(T, len) \
reinterpret_cast<T *>(getmem_atomic_clear((len) * sizeof(T)))
// this replaces all uses of the construction "new T":
#define newitem_atomic(T) reinterpret_cast<T *>(getmem_atomic(sizeof(T)))
// This is used instead of newitem(T) when the size is not known to the c++
// compiler
// Caution: this uses the pointer type, not the struct type.
#define GETMEM(T, size) reinterpret_cast<T>(getmem(size))
#define GETMEM_ATOMIC(T, size) reinterpret_cast<T>(getmem_atomic(size))
struct our_new_delete
{
static inline void *operator new(size_t size)
{
TRAPCHK_SIZE(size);
void *p = getmem(size);
if (p == NULL) outofmem2(size);
TRAPCHK(p);
return p;
}
static inline void *operator new[](size_t size)
{
TRAPCHK_SIZE(size);
void *p = getmem(size);
if (p == NULL) outofmem2(size);
TRAPCHK(p);
return p;
}
static inline void operator delete(void *obj)
{
TRAPCHK(obj);
if (obj != NULL) freemem(obj);
}
static inline void operator delete[](void *obj)
{
TRAPCHK(obj);
if (obj != NULL) freemem(obj);
}
static inline void *operator new(size_t size, void *existing_memory)
{
return existing_memory;
}
static inline void *operator new[](size_t size, void *existing_memory)
{
return existing_memory;
}
static inline void operator delete(void *obj, void *existing_memory)
{
TRAPCHK(obj);
}
static inline void operator delete[](void *obj, void *existing_memory)
{
TRAPCHK(obj);
}
#if !defined(__GNUC__) || defined(__INTEL_COMPILER)
// see Scott Meyers, Effective C++, item 14! This avoids something really bad
// in the c++ standard.
// ... but it slows down destructors in every class inheriting from this one
// gnu cc does it right, running all the destructors, so we don't bother with
// this.
#if 0
// But this will put a pointer to the table of virtual methods at the start of every instance,
// and we don't want that, because we want to pass these pointers to C routines.
// So we can't have any virtual methods here.
virtual ~our_new_delete() {}
#endif
#endif
};
class our_gc_cleanup: public our_new_delete
{
public:
our_gc_cleanup();
virtual ~our_gc_cleanup()
{
if (0 == GC_base(this)) return; // Non-heap object.
#ifdef MEMDEBUG
GC_REGISTER_FINALIZER_IGNORE_SELF(M2_debug_to_outer((void*)this), 0, 0, 0, 0);
#else
GC_REGISTER_FINALIZER_IGNORE_SELF(this, 0, 0, 0, 0);
#endif
}
};
static inline void cleanup(void* obj, void* displ)
{
#ifdef MEMDEBUG
obj = M2_debug_to_inner(obj);
#endif
((our_gc_cleanup*) obj) -> ~our_gc_cleanup();
}
inline our_gc_cleanup::our_gc_cleanup()
{
if (0 == GC_base(this)) return; // Non-heap object.
#ifdef MEMDEBUG
GC_REGISTER_FINALIZER_IGNORE_SELF(M2_debug_to_outer(this), (GC_finalization_proc) cleanup, 0, 0, 0);
#else
GC_REGISTER_FINALIZER_IGNORE_SELF(this, (GC_finalization_proc) cleanup, 0, 0, 0);
#endif
}
#endif
// Local Variables:
// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
// indent-tabs-mode: nil
// End:
|