summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortbsaunde <tbsaunde@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-17 23:08:00 +0000
committertbsaunde <tbsaunde@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-17 23:08:00 +0000
commit92f06184bb548e33327e5c9895b5d00f9e6d0304 (patch)
tree10dcc038bf8bcfb0dd6268ffbf36527b525bfb4e
parent16f97f36c2d368ed6618b8ac65958c0232187b55 (diff)
downloadgcc-92f06184bb548e33327e5c9895b5d00f9e6d0304.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@210568 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/ggc-common.c5
-rw-r--r--gcc/ggc-none.c8
-rw-r--r--gcc/ggc-page.c87
-rw-r--r--gcc/ggc.h71
5 files changed, 182 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1b6f1bd2d40..53dc3e16797 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,29 @@
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.
2014-05-17 Trevor Saunders <tsaunders@mozilla.com>
diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c
index e89cc64b958..b11a10c0072 100644
--- a/gcc/ggc-common.c
+++ b/gcc/ggc-common.c
@@ -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;
}
diff --git a/gcc/ggc-none.c b/gcc/ggc-none.c
index aad89bfe009..97d356657f0 100644
--- a/gcc/ggc-none.c
+++ b/gcc/ggc-none.c
@@ -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);
}
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
index ae5e88ac00e..b3a1a2a103f 100644
--- a/gcc/ggc-page.c
+++ b/gcc/ggc-page.c
@@ -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 ();
diff --git a/gcc/ggc.h b/gcc/ggc.h
index 50fb1995bae..1279aeedc3a 100644
--- a/gcc/ggc.h
+++ b/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);
@@ -157,25 +174,57 @@ extern void dump_ggc_loc_statistics (bool);
((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 *