mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-25 23:41:28 +08:00
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:
parent
04eec98778
commit
de49ce19cc
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 ();
|
||||
|
71
gcc/ggc.h
71
gcc/ggc.h
@ -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 *
|
||||
|
Loading…
x
Reference in New Issue
Block a user