On Tue, May 13, 2014 at 8:41 AM,  <tsaund...@mozilla.com> wrote:
> From: Trevor Saunders <tsaund...@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?

Ok with a comment before ggc_handle_finalizers.

Thanks,
Richard.

> 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
>

Reply via email to