]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
add finalizers to ggc
authorTrevor Saunders <tsaunders@mozilla.com>
Sat, 17 May 2014 23:08:00 +0000 (23:08 +0000)
committerTrevor Saunders <tbsaunde@gcc.gnu.org>
Sat, 17 May 2014 23:08:00 +0000 (23:08 +0000)
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

gcc/ChangeLog
gcc/ggc-common.c
gcc/ggc-none.c
gcc/ggc-page.c
gcc/ggc.h

index 1b6f1bd2d40093c8d2cc03254c6bdd282c346ecf..53dc3e167974d80c83f272045a82aa16111fba84 100644 (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.
index e89cc64b958096195a9e030ea3bc625fa0805818..b11a10c00726911b77c4c044bb767ca0ce98340f 100644 (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;
 }
index aad89bfe00970e9a23d12509dcf05a92a0d6c9b9..97d356657f00d0e0f5e7bb4ea40dd7edfbf4a2b9 100644 (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);
 }
 
index ae5e88ac00ec333f0a816e6cd04137298bb46603..b3a1a2a103fe74f446cdb0d7138032ace41307c1 100644 (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 ();
index 50fb1995bae63f47f6d3e4ac553e136660cd97f8..1279aeedc3a6c9d9d3647b8e1066e7946c1c29a5 100644 (file)
--- 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);
@@ -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 *