diff --git a/src/alloc.c b/src/alloc.c index 41b2f9e..1e9189a 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -3675,6 +3675,7 @@ allocate_misc (enum Lisp_Misc_Type type) misc_objects_consed++; XMISCANY (val)->type = type; XMISCANY (val)->gcmarkbit = 0; + XMISCANY (val)->gcsweepbit = 0; return val; } @@ -6893,6 +6894,24 @@ sweep_misc (void) for (mblk = marker_block; mblk; mblk = *mprev) { register int i; + + for (i = 0; i < lim; i++) + { + if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker) + { + if (!mblk->markers[i].m.u_any.gcmarkbit) + { + mblk->markers[i].m.u_marker.gcsweepbit = 1; + } + } + } + lim = MARKER_BLOCK_SIZE; + mprev = &mblk->next; + } + lim = marker_block_index; + for (mblk = marker_block; mblk; mblk = *mprev) + { + register int i; int this_free = 0; for (i = 0; i < lim; i++) @@ -6900,7 +6919,7 @@ sweep_misc (void) 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); + unchain_collected_markers(mblk->markers[i].m.u_marker.buffer); else if (mblk->markers[i].m.u_any.type == Lisp_Misc_Finalizer) unchain_finalizer (&mblk->markers[i].m.u_finalizer); #ifdef HAVE_MODULES diff --git a/src/lisp.h b/src/lisp.h index f653d85..1af4c34 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2040,14 +2040,16 @@ struct Lisp_Misc_Any /* Supertype of all Misc types. */ { ENUM_BF (Lisp_Misc_Type) type : 16; /* = Lisp_Misc_??? */ bool_bf gcmarkbit : 1; - unsigned spacer : 15; + bool_bf gcsweepbit : 1; + unsigned spacer : 14; }; struct Lisp_Marker { ENUM_BF (Lisp_Misc_Type) type : 16; /* = Lisp_Misc_Marker */ bool_bf gcmarkbit : 1; - unsigned spacer : 13; + bool_bf gcsweepbit : 1; + unsigned spacer : 12; /* This flag is temporarily used in the functions decode/encode_coding_object to record that the marker position must be adjusted after the conversion. */ @@ -3976,6 +3978,7 @@ extern void clear_charpos_cache (struct buffer *); extern ptrdiff_t buf_charpos_to_bytepos (struct buffer *, ptrdiff_t); extern ptrdiff_t buf_bytepos_to_charpos (struct buffer *, ptrdiff_t); extern void unchain_marker (struct Lisp_Marker *marker); +extern void unchain_collected_markers (struct buffer *buffer); extern Lisp_Object set_marker_restricted (Lisp_Object, Lisp_Object, Lisp_Object); extern Lisp_Object set_marker_both (Lisp_Object, Lisp_Object, ptrdiff_t, ptrdiff_t); extern Lisp_Object set_marker_restricted_both (Lisp_Object, Lisp_Object, diff --git a/src/marker.c b/src/marker.c index 05e5bb8..9cd7d26 100644 --- a/src/marker.c +++ b/src/marker.c @@ -629,6 +629,46 @@ unchain_marker (register struct Lisp_Marker *marker) } } +/* Remove all markers that are due to be swept from the chain of + BUFFER, leaving them pointing to nowhere. This is called during + garbage collection, so we must be careful to ignore and preserve + mark bits, including those in chain fields of markers. */ + +void +unchain_collected_markers (register struct buffer *buffer) +{ + register struct Lisp_Marker *tail, **prev; + + if (!buffer) + return; + + /* No dead buffers here. */ + eassert (BUFFER_LIVE_P (buffer)); + + prev = &BUF_MARKERS (buffer); + + for (tail = BUF_MARKERS (buffer); tail; prev = &tail->next, tail = *prev) + if (tail->gcsweepbit) + { + register struct Lisp_Marker *next; + for (next = tail; next && next->gcsweepbit; next = next->next) + { + next->gcsweepbit = 0; + next->buffer = NULL; + } + if (*prev == BUF_MARKERS (buffer)) + { + /* Deleting first marker from the buffer's chain. Crash + if new first marker in chain does not say it belongs + to the same buffer, or at least that they have the same + base buffer. */ + if (next && buffer->text != next->buffer->text) + emacs_abort (); + } + *prev = next; + } +} + /* Return the char position of marker MARKER, as a C integer. */ ptrdiff_t