]> git.eshelyaron.com Git - emacs.git/commitdiff
Clean up gc_sweep
authorDaniel Colascione <dancol@dancol.org>
Sun, 23 Mar 2014 21:58:41 +0000 (14:58 -0700)
committerDaniel Colascione <dancol@dancol.org>
Sun, 23 Mar 2014 21:58:41 +0000 (14:58 -0700)
1  2 
src/ChangeLog
src/alloc.c
src/fns.c

diff --cc src/ChangeLog
index 8b74e921450e274f5691abe0a5858c5cfd628a5d,dc07ba0b320339b70dc7c6c79b49f476ab1eb420..d9e99722319bd3ac241c25a61657571bfc7336a1
@@@ -1,7 -1,3 +1,20 @@@
++2014-03-23  Daniel Colascione  <dancol@dancol.org>
++
++      Split gc_sweep into discrete functions for legibility and better
++      stack traces.
++
++      * alloc.c (sweep_strings,sweep_vectors): Add NO_INLINE
++      (sweep_vectors): Fix typo in comment.
++      (sweep_conses,sweep_floats,sweep_intervals)
++      (sweep_symbols,sweep_misc,sweep_buffers): New functions.
++      (gc_sweep): Call new functions, to which existing functionality is
++      moved.
++      * fns.c (sweep_weak_hash_tables): Add NO_INLINE.
++
 +2014-03-23  Juanma Barranquero  <lekktu@gmail.com>
 +
 +      * w32fns.c (Fw32_shell_execute): Declare `result' only on Cygwin.
 +
  2014-03-23  Daniel Colascione  <dancol@dancol.org>
  
        * xfns.c (create_frame_xic): Pass XNStatusAttributes to XCreateIC
diff --cc src/alloc.c
index 884de3e03e7803d190fbe886975142f1ec3a4431,884de3e03e7803d190fbe886975142f1ec3a4431..e5cd5fed4e3df619e1cf94c75c9618e7c6456775
@@@ -1817,6 -1817,6 +1817,7 @@@ allocate_string_data (struct Lisp_Strin
  
  /* Sweep and compact strings.  */
  
++NO_INLINE /* For better stack traces */
  static void
  sweep_strings (void)
  {
@@@ -2933,6 -2933,6 +2934,7 @@@ cleanup_vector (struct Lisp_Vector *vec
  
  /* Reclaim space used by unmarked vectors.  */
  
++NO_INLINE /* For better stack traces */
  static void
  sweep_vectors (void)
  {
  
              if (vector == (struct Lisp_Vector *) block->data
                  && !VECTOR_IN_BLOCK (next, block))
--              /* This block should be freed because all of it's
++              /* This block should be freed because all of its
                   space was coalesced into the only free vector.  */
                free_this_block = 1;
              else
@@@ -6340,336 -6340,336 +6342,353 @@@ survives_gc_p (Lisp_Object obj
  
  
  \f
--/* Sweep: find all structures not marked, and free them.  */
  
++NO_INLINE /* For better stack traces */
  static void
--gc_sweep (void)
++sweep_conses (void)
  {
--  /* Remove or mark entries in weak hash tables.
--     This must be done before any object is unmarked.  */
--  sweep_weak_hash_tables ();
--
--  sweep_strings ();
--  check_string_bytes (!noninteractive);
--
--  /* Put all unmarked conses on free list.  */
--  {
--    register struct cons_block *cblk;
--    struct cons_block **cprev = &cons_block;
--    register int lim = cons_block_index;
--    EMACS_INT num_free = 0, num_used = 0;
++  register struct cons_block *cblk;
++  struct cons_block **cprev = &cons_block;
++  register int lim = cons_block_index;
++  EMACS_INT num_free = 0, num_used = 0;
  
--    cons_free_list = 0;
++  cons_free_list = 0;
  
--    for (cblk = cons_block; cblk; cblk = *cprev)
--      {
--      register int i = 0;
--      int this_free = 0;
--      int ilim = (lim + BITS_PER_INT - 1) / BITS_PER_INT;
++  for (cblk = cons_block; cblk; cblk = *cprev)
++    {
++      register int i = 0;
++      int this_free = 0;
++      int ilim = (lim + BITS_PER_INT - 1) / BITS_PER_INT;
  
--      /* Scan the mark bits an int at a time.  */
--      for (i = 0; i < ilim; i++)
--        {
--          if (cblk->gcmarkbits[i] == -1)
--            {
--              /* Fast path - all cons cells for this int are marked.  */
--              cblk->gcmarkbits[i] = 0;
--              num_used += BITS_PER_INT;
--            }
--          else
--            {
--              /* Some cons cells for this int are not marked.
--                 Find which ones, and free them.  */
--              int start, pos, stop;
--
--              start = i * BITS_PER_INT;
--              stop = lim - start;
--              if (stop > BITS_PER_INT)
--                stop = BITS_PER_INT;
--              stop += start;
--
--              for (pos = start; pos < stop; pos++)
--                {
--                  if (!CONS_MARKED_P (&cblk->conses[pos]))
--                    {
--                      this_free++;
--                      cblk->conses[pos].u.chain = cons_free_list;
--                      cons_free_list = &cblk->conses[pos];
++      /* Scan the mark bits an int at a time.  */
++      for (i = 0; i < ilim; i++)
++        {
++          if (cblk->gcmarkbits[i] == -1)
++            {
++              /* Fast path - all cons cells for this int are marked.  */
++              cblk->gcmarkbits[i] = 0;
++              num_used += BITS_PER_INT;
++            }
++          else
++            {
++              /* Some cons cells for this int are not marked.
++                 Find which ones, and free them.  */
++              int start, pos, stop;
++
++              start = i * BITS_PER_INT;
++              stop = lim - start;
++              if (stop > BITS_PER_INT)
++                stop = BITS_PER_INT;
++              stop += start;
++
++              for (pos = start; pos < stop; pos++)
++                {
++                  if (!CONS_MARKED_P (&cblk->conses[pos]))
++                    {
++                      this_free++;
++                      cblk->conses[pos].u.chain = cons_free_list;
++                      cons_free_list = &cblk->conses[pos];
  #if GC_MARK_STACK
--                      cons_free_list->car = Vdead;
++                      cons_free_list->car = Vdead;
  #endif
--                    }
--                  else
--                    {
--                      num_used++;
--                      CONS_UNMARK (&cblk->conses[pos]);
--                    }
--                }
--            }
--        }
--
--      lim = CONS_BLOCK_SIZE;
--      /* If this block contains only free conses and we have already
--         seen more than two blocks worth of free conses then deallocate
--         this block.  */
--      if (this_free == CONS_BLOCK_SIZE && num_free > CONS_BLOCK_SIZE)
--        {
--          *cprev = cblk->next;
--          /* Unhook from the free list.  */
--          cons_free_list = cblk->conses[0].u.chain;
--          lisp_align_free (cblk);
--        }
--      else
--        {
--          num_free += this_free;
--          cprev = &cblk->next;
--        }
--      }
--    total_conses = num_used;
--    total_free_conses = num_free;
--  }
++                    }
++                  else
++                    {
++                      num_used++;
++                      CONS_UNMARK (&cblk->conses[pos]);
++                    }
++                }
++            }
++        }
  
--  /* Put all unmarked floats on free list.  */
--  {
--    register struct float_block *fblk;
--    struct float_block **fprev = &float_block;
--    register int lim = float_block_index;
--    EMACS_INT num_free = 0, num_used = 0;
++      lim = CONS_BLOCK_SIZE;
++      /* If this block contains only free conses and we have already
++         seen more than two blocks worth of free conses then deallocate
++         this block.  */
++      if (this_free == CONS_BLOCK_SIZE && num_free > CONS_BLOCK_SIZE)
++        {
++          *cprev = cblk->next;
++          /* Unhook from the free list.  */
++          cons_free_list = cblk->conses[0].u.chain;
++          lisp_align_free (cblk);
++        }
++      else
++        {
++          num_free += this_free;
++          cprev = &cblk->next;
++        }
++    }
++  total_conses = num_used;
++  total_free_conses = num_free;
++}
  
--    float_free_list = 0;
++NO_INLINE /* For better stack traces */
++static void
++sweep_floats (void)
++{
++  register struct float_block *fblk;
++  struct float_block **fprev = &float_block;
++  register int lim = float_block_index;
++  EMACS_INT num_free = 0, num_used = 0;
  
--    for (fblk = float_block; fblk; fblk = *fprev)
--      {
--      register int i;
--      int this_free = 0;
--      for (i = 0; i < lim; i++)
--        if (!FLOAT_MARKED_P (&fblk->floats[i]))
--          {
--            this_free++;
--            fblk->floats[i].u.chain = float_free_list;
--            float_free_list = &fblk->floats[i];
--          }
--        else
--          {
--            num_used++;
--            FLOAT_UNMARK (&fblk->floats[i]);
--          }
--      lim = FLOAT_BLOCK_SIZE;
--      /* If this block contains only free floats and we have already
--         seen more than two blocks worth of free floats then deallocate
--         this block.  */
--      if (this_free == FLOAT_BLOCK_SIZE && num_free > FLOAT_BLOCK_SIZE)
--        {
--          *fprev = fblk->next;
--          /* Unhook from the free list.  */
--          float_free_list = fblk->floats[0].u.chain;
--          lisp_align_free (fblk);
--        }
--      else
--        {
--          num_free += this_free;
--          fprev = &fblk->next;
--        }
--      }
--    total_floats = num_used;
--    total_free_floats = num_free;
--  }
++  float_free_list = 0;
  
--  /* Put all unmarked intervals on free list.  */
--  {
--    register struct interval_block *iblk;
--    struct interval_block **iprev = &interval_block;
--    register int lim = interval_block_index;
--    EMACS_INT num_free = 0, num_used = 0;
++  for (fblk = float_block; fblk; fblk = *fprev)
++    {
++      register int i;
++      int this_free = 0;
++      for (i = 0; i < lim; i++)
++        if (!FLOAT_MARKED_P (&fblk->floats[i]))
++          {
++            this_free++;
++            fblk->floats[i].u.chain = float_free_list;
++            float_free_list = &fblk->floats[i];
++          }
++        else
++          {
++            num_used++;
++            FLOAT_UNMARK (&fblk->floats[i]);
++          }
++      lim = FLOAT_BLOCK_SIZE;
++      /* If this block contains only free floats and we have already
++         seen more than two blocks worth of free floats then deallocate
++         this block.  */
++      if (this_free == FLOAT_BLOCK_SIZE && num_free > FLOAT_BLOCK_SIZE)
++        {
++          *fprev = fblk->next;
++          /* Unhook from the free list.  */
++          float_free_list = fblk->floats[0].u.chain;
++          lisp_align_free (fblk);
++        }
++      else
++        {
++          num_free += this_free;
++          fprev = &fblk->next;
++        }
++    }
++  total_floats = num_used;
++  total_free_floats = num_free;
++}
  
--    interval_free_list = 0;
++NO_INLINE /* For better stack traces */
++static void
++sweep_intervals (void)
++{
++  register struct interval_block *iblk;
++  struct interval_block **iprev = &interval_block;
++  register int lim = interval_block_index;
++  EMACS_INT num_free = 0, num_used = 0;
  
--    for (iblk = interval_block; iblk; iblk = *iprev)
--      {
--      register int i;
--      int this_free = 0;
++  interval_free_list = 0;
  
--      for (i = 0; i < lim; i++)
--        {
--          if (!iblk->intervals[i].gcmarkbit)
--            {
--              set_interval_parent (&iblk->intervals[i], interval_free_list);
--              interval_free_list = &iblk->intervals[i];
--              this_free++;
--            }
--          else
--            {
--              num_used++;
--              iblk->intervals[i].gcmarkbit = 0;
--            }
--        }
--      lim = INTERVAL_BLOCK_SIZE;
--      /* If this block contains only free intervals and we have already
--         seen more than two blocks worth of free intervals then
--         deallocate this block.  */
--      if (this_free == INTERVAL_BLOCK_SIZE && num_free > INTERVAL_BLOCK_SIZE)
--        {
--          *iprev = iblk->next;
--          /* Unhook from the free list.  */
--          interval_free_list = INTERVAL_PARENT (&iblk->intervals[0]);
--          lisp_free (iblk);
--        }
--      else
--        {
--          num_free += this_free;
--          iprev = &iblk->next;
--        }
--      }
--    total_intervals = num_used;
--    total_free_intervals = num_free;
--  }
++  for (iblk = interval_block; iblk; iblk = *iprev)
++    {
++      register int i;
++      int this_free = 0;
  
--  /* Put all unmarked symbols on free list.  */
--  {
--    register struct symbol_block *sblk;
--    struct symbol_block **sprev = &symbol_block;
--    register int lim = symbol_block_index;
--    EMACS_INT num_free = 0, num_used = 0;
++      for (i = 0; i < lim; i++)
++        {
++          if (!iblk->intervals[i].gcmarkbit)
++            {
++              set_interval_parent (&iblk->intervals[i], interval_free_list);
++              interval_free_list = &iblk->intervals[i];
++              this_free++;
++            }
++          else
++            {
++              num_used++;
++              iblk->intervals[i].gcmarkbit = 0;
++            }
++        }
++      lim = INTERVAL_BLOCK_SIZE;
++      /* If this block contains only free intervals and we have already
++         seen more than two blocks worth of free intervals then
++         deallocate this block.  */
++      if (this_free == INTERVAL_BLOCK_SIZE && num_free > INTERVAL_BLOCK_SIZE)
++        {
++          *iprev = iblk->next;
++          /* Unhook from the free list.  */
++          interval_free_list = INTERVAL_PARENT (&iblk->intervals[0]);
++          lisp_free (iblk);
++        }
++      else
++        {
++          num_free += this_free;
++          iprev = &iblk->next;
++        }
++    }
++  total_intervals = num_used;
++  total_free_intervals = num_free;
++}
  
--    symbol_free_list = NULL;
++NO_INLINE /* For better stack traces */
++static void
++sweep_symbols (void)
++{
++  register struct symbol_block *sblk;
++  struct symbol_block **sprev = &symbol_block;
++  register int lim = symbol_block_index;
++  EMACS_INT num_free = 0, num_used = 0;
  
--    for (sblk = symbol_block; sblk; sblk = *sprev)
--      {
--      int this_free = 0;
--      union aligned_Lisp_Symbol *sym = sblk->symbols;
--      union aligned_Lisp_Symbol *end = sym + lim;
++  symbol_free_list = NULL;
  
--      for (; sym < end; ++sym)
--        {
--          /* Check if the symbol was created during loadup.  In such a case
--             it might be pointed to by pure bytecode which we don't trace,
--             so we conservatively assume that it is live.  */
--          bool pure_p = PURE_POINTER_P (XSTRING (sym->s.name));
++  for (sblk = symbol_block; sblk; sblk = *sprev)
++    {
++      int this_free = 0;
++      union aligned_Lisp_Symbol *sym = sblk->symbols;
++      union aligned_Lisp_Symbol *end = sym + lim;
  
--          if (!sym->s.gcmarkbit && !pure_p)
--            {
--              if (sym->s.redirect == SYMBOL_LOCALIZED)
--                xfree (SYMBOL_BLV (&sym->s));
--              sym->s.next = symbol_free_list;
--              symbol_free_list = &sym->s;
++      for (; sym < end; ++sym)
++        {
++          /* Check if the symbol was created during loadup.  In such a case
++             it might be pointed to by pure bytecode which we don't trace,
++             so we conservatively assume that it is live.  */
++          bool pure_p = PURE_POINTER_P (XSTRING (sym->s.name));
++
++          if (!sym->s.gcmarkbit && !pure_p)
++            {
++              if (sym->s.redirect == SYMBOL_LOCALIZED)
++                xfree (SYMBOL_BLV (&sym->s));
++              sym->s.next = symbol_free_list;
++              symbol_free_list = &sym->s;
  #if GC_MARK_STACK
--              symbol_free_list->function = Vdead;
++              symbol_free_list->function = Vdead;
  #endif
--              ++this_free;
--            }
--          else
--            {
--              ++num_used;
--              if (!pure_p)
--                eassert (!STRING_MARKED_P (XSTRING (sym->s.name)));
--              sym->s.gcmarkbit = 0;
--            }
--        }
++              ++this_free;
++            }
++          else
++            {
++              ++num_used;
++              if (!pure_p)
++                eassert (!STRING_MARKED_P (XSTRING (sym->s.name)));
++              sym->s.gcmarkbit = 0;
++            }
++        }
  
--      lim = SYMBOL_BLOCK_SIZE;
--      /* If this block contains only free symbols and we have already
--         seen more than two blocks worth of free symbols then deallocate
--         this block.  */
--      if (this_free == SYMBOL_BLOCK_SIZE && num_free > SYMBOL_BLOCK_SIZE)
--        {
--          *sprev = sblk->next;
--          /* Unhook from the free list.  */
--          symbol_free_list = sblk->symbols[0].s.next;
--          lisp_free (sblk);
--        }
--      else
--        {
--          num_free += this_free;
--          sprev = &sblk->next;
--        }
--      }
--    total_symbols = num_used;
--    total_free_symbols = num_free;
--  }
++      lim = SYMBOL_BLOCK_SIZE;
++      /* If this block contains only free symbols and we have already
++         seen more than two blocks worth of free symbols then deallocate
++         this block.  */
++      if (this_free == SYMBOL_BLOCK_SIZE && num_free > SYMBOL_BLOCK_SIZE)
++        {
++          *sprev = sblk->next;
++          /* Unhook from the free list.  */
++          symbol_free_list = sblk->symbols[0].s.next;
++          lisp_free (sblk);
++        }
++      else
++        {
++          num_free += this_free;
++          sprev = &sblk->next;
++        }
++    }
++  total_symbols = num_used;
++  total_free_symbols = num_free;
++}
  
--  /* Put all unmarked misc's on free list.
--     For a marker, first unchain it from the buffer it points into.  */
--  {
--    register struct marker_block *mblk;
--    struct marker_block **mprev = &marker_block;
--    register int lim = marker_block_index;
--    EMACS_INT num_free = 0, num_used = 0;
++NO_INLINE /* For better stack traces */
++static void
++sweep_misc (void)
++{
++  register struct marker_block *mblk;
++  struct marker_block **mprev = &marker_block;
++  register int lim = marker_block_index;
++  EMACS_INT num_free = 0, num_used = 0;
  
--    marker_free_list = 0;
++  /* Put all unmarked misc's on free list.  For a marker, first
++     unchain it from the buffer it points into.  */
  
--    for (mblk = marker_block; mblk; mblk = *mprev)
--      {
--      register int i;
--      int this_free = 0;
++  marker_free_list = 0;
  
--      for (i = 0; i < lim; i++)
--        {
--          if (!mblk->markers[i].m.u_any.gcmarkbit)
--            {
--              if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker)
--                unchain_marker (&mblk->markers[i].m.u_marker);
--              /* Set the type of the freed object to Lisp_Misc_Free.
--                 We could leave the type alone, since nobody checks it,
--                 but this might catch bugs faster.  */
--              mblk->markers[i].m.u_marker.type = Lisp_Misc_Free;
--              mblk->markers[i].m.u_free.chain = marker_free_list;
--              marker_free_list = &mblk->markers[i].m;
--              this_free++;
--            }
--          else
--            {
--              num_used++;
--              mblk->markers[i].m.u_any.gcmarkbit = 0;
--            }
--        }
--      lim = MARKER_BLOCK_SIZE;
--      /* If this block contains only free markers and we have already
--         seen more than two blocks worth of free markers then deallocate
--         this block.  */
--      if (this_free == MARKER_BLOCK_SIZE && num_free > MARKER_BLOCK_SIZE)
--        {
--          *mprev = mblk->next;
--          /* Unhook from the free list.  */
--          marker_free_list = mblk->markers[0].m.u_free.chain;
--          lisp_free (mblk);
--        }
--      else
--        {
--          num_free += this_free;
--          mprev = &mblk->next;
--        }
--      }
++  for (mblk = marker_block; mblk; mblk = *mprev)
++    {
++      register int i;
++      int this_free = 0;
  
--    total_markers = num_used;
--    total_free_markers = num_free;
--  }
++      for (i = 0; i < lim; i++)
++        {
++          if (!mblk->markers[i].m.u_any.gcmarkbit)
++            {
++              if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker)
++                unchain_marker (&mblk->markers[i].m.u_marker);
++              /* Set the type of the freed object to Lisp_Misc_Free.
++                 We could leave the type alone, since nobody checks it,
++                 but this might catch bugs faster.  */
++              mblk->markers[i].m.u_marker.type = Lisp_Misc_Free;
++              mblk->markers[i].m.u_free.chain = marker_free_list;
++              marker_free_list = &mblk->markers[i].m;
++              this_free++;
++            }
++          else
++            {
++              num_used++;
++              mblk->markers[i].m.u_any.gcmarkbit = 0;
++            }
++        }
++      lim = MARKER_BLOCK_SIZE;
++      /* If this block contains only free markers and we have already
++         seen more than two blocks worth of free markers then deallocate
++         this block.  */
++      if (this_free == MARKER_BLOCK_SIZE && num_free > MARKER_BLOCK_SIZE)
++        {
++          *mprev = mblk->next;
++          /* Unhook from the free list.  */
++          marker_free_list = mblk->markers[0].m.u_free.chain;
++          lisp_free (mblk);
++        }
++      else
++        {
++          num_free += this_free;
++          mprev = &mblk->next;
++        }
++    }
  
--  /* Free all unmarked buffers */
--  {
--    register struct buffer *buffer, **bprev = &all_buffers;
++  total_markers = num_used;
++  total_free_markers = num_free;
++}
  
--    total_buffers = 0;
--    for (buffer = all_buffers; buffer; buffer = *bprev)
--      if (!VECTOR_MARKED_P (buffer))
--      {
--        *bprev = buffer->next;
--        lisp_free (buffer);
--      }
--      else
--      {
--        VECTOR_UNMARK (buffer);
--        /* Do not use buffer_(set|get)_intervals here.  */
--        buffer->text->intervals = balance_intervals (buffer->text->intervals);
--        total_buffers++;
--        bprev = &buffer->next;
--      }
--  }
++NO_INLINE /* For better stack traces */
++static void
++sweep_buffers (void)
++{
++  register struct buffer *buffer, **bprev = &all_buffers;
  
--  sweep_vectors ();
--  check_string_bytes (!noninteractive);
++  total_buffers = 0;
++  for (buffer = all_buffers; buffer; buffer = *bprev)
++    if (!VECTOR_MARKED_P (buffer))
++      {
++        *bprev = buffer->next;
++        lisp_free (buffer);
++      }
++    else
++      {
++        VECTOR_UNMARK (buffer);
++        /* Do not use buffer_(set|get)_intervals here.  */
++        buffer->text->intervals = balance_intervals (buffer->text->intervals);
++        total_buffers++;
++        bprev = &buffer->next;
++      }
  }
  
++/* Sweep: find all structures not marked, and free them.  */
++static void
++gc_sweep (void)
++{
++  /* Remove or mark entries in weak hash tables.
++     This must be done before any object is unmarked.  */
++  sweep_weak_hash_tables ();
  
++  sweep_strings ();
++  check_string_bytes (!noninteractive);
++  sweep_conses ();
++  sweep_floats ();
++  sweep_intervals ();
++  sweep_symbols ();
++  sweep_misc ();
++  sweep_buffers ();
++  sweep_vectors ();
++  check_string_bytes (!noninteractive);
++}
  
  \f
  /* Debugging aids.  */
diff --cc src/fns.c
index 499e4b490a6f508221d01d15918655d2b5e4510a,499e4b490a6f508221d01d15918655d2b5e4510a..cf799344c329f801b52ac3df94e7e2c61a2131ea
+++ b/src/fns.c
@@@ -4032,6 -4032,6 +4032,7 @@@ sweep_weak_table (struct Lisp_Hash_Tabl
     current garbage collection.  Remove weak tables that don't survive
     from Vweak_hash_tables.  Called from gc_sweep.  */
  
++NO_INLINE /* For better stack traces */
  void
  sweep_weak_hash_tables (void)
  {