This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 4/5] add finalizers to ggc


From: Trevor Saunders <tsaunders@mozilla.com>

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.

This uses the two vector and forward iteration approach I think richi agreed to.

bootstrapped + regtested on x86_64-unknown-linux-gnu ok?

Trev

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.
---
 gcc/ggc-common.c |  5 ++--
 gcc/ggc-none.c   |  8 ++++--
 gcc/ggc-page.c   | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gcc/ggc.h        | 71 +++++++++++++++++++++++++++++++++++++++------
 4 files changed, 158 insertions(+), 13 deletions(-)

diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c
index e89cc64..b11a10c 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 aad89bf..97d3566 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 ae5e88a..b3a1a2a 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 50fb199..1279aee 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 *
-- 
2.0.0.rc2


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]