diff --git a/src/ChangeLog b/src/ChangeLog index 8b74e921450..d9e99722319 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,16 @@ +2014-03-23 Daniel Colascione + + 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 * w32fns.c (Fw32_shell_execute): Declare `result' only on Cygwin. diff --git a/src/alloc.c b/src/alloc.c index 884de3e03e7..e5cd5fed4e3 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1817,6 +1817,7 @@ allocate_string_data (struct Lisp_String *s, /* Sweep and compact strings. */ +NO_INLINE /* For better stack traces */ static void sweep_strings (void) { @@ -2933,6 +2934,7 @@ cleanup_vector (struct Lisp_Vector *vector) /* Reclaim space used by unmarked vectors. */ +NO_INLINE /* For better stack traces */ static void sweep_vectors (void) { @@ -2987,7 +2989,7 @@ 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,8 +6342,335 @@ survives_gc_p (Lisp_Object obj) -/* Sweep: find all structures not marked, and free them. */ +NO_INLINE /* For better stack traces */ +static void +sweep_conses (void) +{ + 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; + + 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]; +#if GC_MARK_STACK + 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; +} + +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; + + float_free_list = 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; +} + +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; + + interval_free_list = 0; + + for (iblk = interval_block; iblk; iblk = *iprev) + { + register int i; + int this_free = 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; +} + +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; + + symbol_free_list = NULL; + + 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; + + 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; +#endif + ++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; +} + +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; + + /* Put all unmarked misc's on free list. For a marker, first + unchain it from the buffer it points into. */ + + marker_free_list = 0; + + for (mblk = marker_block; mblk; mblk = *mprev) + { + register int i; + int this_free = 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; + } + } + + total_markers = num_used; + total_free_markers = num_free; +} + +NO_INLINE /* For better stack traces */ +static void +sweep_buffers (void) +{ + register struct buffer *buffer, **bprev = &all_buffers; + + 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) { @@ -6351,326 +6680,16 @@ gc_sweep (void) 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; - - 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; - - /* 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; -#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; - } - - /* 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; - - float_free_list = 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; - } - - /* 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; - - interval_free_list = 0; - - for (iblk = interval_block; iblk; iblk = *iprev) - { - register int i; - int this_free = 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; - } - - /* 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; - - symbol_free_list = NULL; - - 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; - - 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; -#endif - ++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; - } - - /* 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; - - marker_free_list = 0; - - for (mblk = marker_block; mblk; mblk = *mprev) - { - register int i; - int this_free = 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; - } - } - - total_markers = num_used; - total_free_markers = num_free; - } - - /* Free all unmarked buffers */ - { - register struct buffer *buffer, **bprev = &all_buffers; - - 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_conses (); + sweep_floats (); + sweep_intervals (); + sweep_symbols (); + sweep_misc (); + sweep_buffers (); sweep_vectors (); check_string_bytes (!noninteractive); } - - /* Debugging aids. */ diff --git a/src/fns.c b/src/fns.c index 499e4b490a6..cf799344c32 100644 --- a/src/fns.c +++ b/src/fns.c @@ -4032,6 +4032,7 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p) 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) {