add finalizers to ggc

This implements finalizers by keeping a list of registered finalizers
and after every mark but before sweeping check to see if any of them are
for unmarked blocks.

gcc/ChangeLog:

	* ggc-common.c (ggc_internal_cleared_alloc): Adjust.
	* ggc-none.c (ggc_internal_alloc): Assert if a finalizer is passed.
	(ggc_internal_cleared_alloc): Likewise.
	* ggc-page.c (finalizer): New class.
(vec_finalizer): Likewise.
	(globals::finalizers): New member.
(globals::vec_finalizers): Likewise.
	(ggc_internal_alloc): Record the finalizer if any for the block being
	allocated.
	(ggc_handle_finalizers): New function.
	(ggc_collect): Call ggc_handle_finalizers.
	* ggc.h (ggc_internal_alloc): Add arguments to allow installing a
	finalizer.
	(ggc_internal_cleared_alloc): Likewise.
	(finalize): New function.
	(need_finalization_p): Likewise.
	(ggc_alloc): Install the type's destructor as the finalizer if it
	might do something.
	(ggc_cleared_alloc): Likewise.
	(ggc_vec_alloc): Likewise.
	(ggc_cleared_vec_alloc): Likewise.

From-SVN: r210568
This commit is contained in:
Trevor Saunders 2014-05-17 23:08:00 +00:00 committed by Trevor Saunders
parent 04eec98778
commit de49ce19cc
5 changed files with 182 additions and 13 deletions

View File

@ -1,3 +1,27 @@
2014-05-17 Trevor Saunders <tsaunders@mozilla.com>
* ggc-common.c (ggc_internal_cleared_alloc): Adjust.
* ggc-none.c (ggc_internal_alloc): Assert if a finalizer is passed.
(ggc_internal_cleared_alloc): Likewise.
* ggc-page.c (finalizer): New class.
(vec_finalizer): Likewise.
(globals::finalizers): New member.
(globals::vec_finalizers): Likewise.
(ggc_internal_alloc): Record the finalizer if any for the block being
allocated.
(ggc_handle_finalizers): New function.
(ggc_collect): Call ggc_handle_finalizers.
* ggc.h (ggc_internal_alloc): Add arguments to allow installing a
finalizer.
(ggc_internal_cleared_alloc): Likewise.
(finalize): New function.
(need_finalization_p): Likewise.
(ggc_alloc): Install the type's destructor as the finalizer if it
might do something.
(ggc_cleared_alloc): Likewise.
(ggc_vec_alloc): Likewise.
(ggc_cleared_vec_alloc): Likewise.
2014-05-17 Trevor Saunders <tsaunders@mozilla.com>
* ggc.h (ggc_alloc_cleared_simd_clone_stat): Remove function.

View File

@ -174,9 +174,10 @@ ggc_mark_roots (void)
/* Allocate a block of memory, then clear it. */
void *
ggc_internal_cleared_alloc (size_t size MEM_STAT_DECL)
ggc_internal_cleared_alloc (size_t size, void (*f)(void *), size_t s, size_t n
MEM_STAT_DECL)
{
void *buf = ggc_internal_alloc (size PASS_MEM_STAT);
void *buf = ggc_internal_alloc (size, f, s, n PASS_MEM_STAT);
memset (buf, 0, size);
return buf;
}

View File

@ -41,14 +41,18 @@ ggc_round_alloc_size (size_t requested_size)
}
void *
ggc_internal_alloc (size_t size MEM_STAT_DECL)
ggc_internal_alloc (size_t size, void (*f)(void *), size_t, size_t
MEM_STAT_DECL)
{
gcc_assert (!f); // ggc-none doesn't support finalizers
return xmalloc (size);
}
void *
ggc_internal_cleared_alloc (size_t size MEM_STAT_DECL)
ggc_internal_cleared_alloc (size_t size, void (*f)(void *), size_t, size_t
MEM_STAT_DECL)
{
gcc_assert (!f); // ggc-none doesn't support finalizers
return xcalloc (size, 1);
}

View File

@ -332,6 +332,41 @@ typedef struct page_table_chain
#endif
class finalizer
{
public:
finalizer (void *addr, void (*f)(void *)) : m_addr (addr), m_function (f) {}
void *addr () const { return m_addr; }
void call () const { m_function (m_addr); }
private:
void *m_addr;
void (*m_function)(void *);
};
class vec_finalizer
{
public:
vec_finalizer (uintptr_t addr, void (*f)(void *), size_t s, size_t n) :
m_addr (addr), m_function (f), m_object_size (s), m_n_objects (n) {}
void call () const
{
for (size_t i = 0; i < m_n_objects; i++)
m_function (reinterpret_cast<void *> (m_addr + (i * m_object_size)));
}
void *addr () const { return reinterpret_cast<void *> (m_addr); }
private:
uintptr_t m_addr;
void (*m_function)(void *);
size_t m_object_size;
size_t m_n_objects;
};
#ifdef ENABLE_GC_ALWAYS_COLLECT
/* List of free objects to be verified as actually free on the
next collection. */
@ -425,6 +460,12 @@ static struct globals
better runtime data access pattern. */
unsigned long **save_in_use;
/* Finalizers for single objects. */
vec<finalizer> finalizers;
/* Finalizers for vectors of objects. */
vec<vec_finalizer> vec_finalizers;
#ifdef ENABLE_GC_ALWAYS_COLLECT
/* List of free objects to be verified as actually free on the
next collection. */
@ -1202,7 +1243,8 @@ ggc_round_alloc_size (size_t requested_size)
/* Allocate a chunk of memory of SIZE bytes. Its contents are undefined. */
void *
ggc_internal_alloc (size_t size MEM_STAT_DECL)
ggc_internal_alloc (size_t size, void (*f)(void *), size_t s, size_t n
MEM_STAT_DECL)
{
size_t order, word, bit, object_offset, object_size;
struct page_entry *entry;
@ -1345,6 +1387,12 @@ ggc_internal_alloc (size_t size MEM_STAT_DECL)
/* For timevar statistics. */
timevar_ggc_mem_total += object_size;
if (f && n == 1)
G.finalizers.safe_push (finalizer (result, f));
else if (f)
G.vec_finalizers.safe_push
(vec_finalizer (reinterpret_cast<uintptr_t> (result), f, s, n));
if (GATHER_STATISTICS)
{
size_t overhead = object_size - size;
@ -1811,6 +1859,42 @@ clear_marks (void)
}
}
static void
ggc_handle_finalizers ()
{
if (G.context_depth != 0)
return;
unsigned length = G.finalizers.length ();
for (unsigned int i = 0; i < length;)
{
finalizer &f = G.finalizers[i];
if (!ggc_marked_p (f.addr ()))
{
f.call ();
G.finalizers.unordered_remove (i);
length--;
}
else
i++;
}
length = G.vec_finalizers.length ();
for (unsigned int i = 0; i < length;)
{
vec_finalizer &f = G.vec_finalizers[i];
if (!ggc_marked_p (f.addr ()))
{
f.call ();
G.vec_finalizers.unordered_remove (i);
length--;
}
else
i++;
}
}
/* Free all empty pages. Partially empty pages need no attention
because the `mark' bit doubles as an `unused' bit. */
@ -2075,6 +2159,7 @@ ggc_collect (void)
clear_marks ();
ggc_mark_roots ();
ggc_handle_finalizers ();
if (GATHER_STATISTICS)
ggc_prune_overhead_list ();

View File

@ -136,13 +136,30 @@ extern void gt_pch_save (FILE *f);
/* Allocation. */
/* The internal primitive. */
extern void *ggc_internal_alloc (size_t CXX_MEM_STAT_INFO) ATTRIBUTE_MALLOC;
extern void *ggc_internal_alloc (size_t, void (*)(void *), size_t,
size_t CXX_MEM_STAT_INFO)
ATTRIBUTE_MALLOC;
static inline
void *
ggc_internal_alloc (size_t s CXX_MEM_STAT_INFO)
{
return ggc_internal_alloc (s, NULL, 0, 1 PASS_MEM_STAT);
}
extern size_t ggc_round_alloc_size (size_t requested_size);
/* Allocates cleared memory. */
extern void *ggc_internal_cleared_alloc (size_t CXX_MEM_STAT_INFO)
ATTRIBUTE_MALLOC;
extern void *ggc_internal_cleared_alloc (size_t, void (*)(void *),
size_t, size_t
CXX_MEM_STAT_INFO) ATTRIBUTE_MALLOC;
static inline
void *
ggc_internal_cleared_alloc (size_t s CXX_MEM_STAT_INFO)
{
return ggc_internal_cleared_alloc (s, NULL, 0, 1 PASS_MEM_STAT);
}
/* Resize a block. */
extern void *ggc_realloc (void *, size_t CXX_MEM_STAT_INFO);
@ -156,26 +173,58 @@ extern void dump_ggc_loc_statistics (bool);
#define GGC_RESIZEVEC(T, P, N) \
((T *) ggc_realloc ((P), (N) * sizeof (T) MEM_STAT_INFO))
template<typename T>
void
finalize (void *p)
{
static_cast<T *> (p)->~T ();
}
template<typename T>
static inline bool
need_finalization_p ()
{
#if GCC_VERSION >= 4003
return !__has_trivial_destructor (T);
#else
return true;
#endif
}
template<typename T>
static inline T *
ggc_alloc (ALONE_CXX_MEM_STAT_INFO)
{
return static_cast<T *> (ggc_internal_alloc (sizeof (T) PASS_MEM_STAT));
if (need_finalization_p<T> ())
return static_cast<T *> (ggc_internal_alloc (sizeof (T), finalize<T>, 0, 1
PASS_MEM_STAT));
else
return static_cast<T *> (ggc_internal_alloc (sizeof (T), NULL, 0, 1
PASS_MEM_STAT));
}
template<typename T>
static inline T *
ggc_cleared_alloc (ALONE_CXX_MEM_STAT_INFO)
{
return static_cast<T *> (ggc_internal_cleared_alloc (sizeof (T)
PASS_MEM_STAT));
if (need_finalization_p<T> ())
return static_cast<T *> (ggc_internal_cleared_alloc (sizeof (T),
finalize<T>, 0, 1
PASS_MEM_STAT));
else
return static_cast<T *> (ggc_internal_cleared_alloc (sizeof (T), NULL, 0, 1
PASS_MEM_STAT));
}
template<typename T>
static inline T *
ggc_vec_alloc (size_t c CXX_MEM_STAT_INFO)
{
return static_cast<T *> (ggc_internal_alloc (c * sizeof (T)
if (need_finalization_p<T> ())
return static_cast<T *> (ggc_internal_alloc (c * sizeof (T), finalize<T>,
sizeof (T), c PASS_MEM_STAT));
else
return static_cast<T *> (ggc_internal_alloc (c * sizeof (T), NULL, 0, 0
PASS_MEM_STAT));
}
@ -183,8 +232,14 @@ template<typename T>
static inline T *
ggc_cleared_vec_alloc (size_t c CXX_MEM_STAT_INFO)
{
return static_cast<T *> (ggc_internal_cleared_alloc (c * sizeof (T)
if (need_finalization_p<T> ())
return static_cast<T *> (ggc_internal_cleared_alloc (c * sizeof (T),
finalize<T>,
sizeof (T), c
PASS_MEM_STAT));
else
return static_cast<T *> (ggc_internal_cleared_alloc (c * sizeof (T), NULL,
0, 0 PASS_MEM_STAT));
}
static inline void *