aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2018-03-23 11:09:54 -0400
committerStefan Monnier2018-03-23 11:09:54 -0400
commitcf3164523b32f01dbaad2c1364ecf2dcf8f22aa5 (patch)
tree9dca9f6732e7b55b0285af36ff2de87919d4dde9
parent6695c1be51bd8a1e208ae02505b2a6fa64c85e68 (diff)
downloademacs-cf3164523b32f01dbaad2c1364ecf2dcf8f22aa5.tar.gz
emacs-cf3164523b32f01dbaad2c1364ecf2dcf8f22aa5.zip
* src/alloc.c: Avoid O(N²) complexity when unchaining markers (bug#24548).
Unchain all dead markers with a single scan of the markers list, instead of calling the O(N) 'unchain_marker' N times. (unchain_dead_markers): New function. (sweep_buffers): Use it. (gc_sweep): Sweep buffers before markers. (sweep_misc): Check that markers have been unchained when reclaiming them.
-rw-r--r--src/alloc.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/src/alloc.c b/src/alloc.c
index da01173fba2..5eaf7cbc1c6 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -7095,7 +7095,9 @@ sweep_misc (void)
7095 if (!mblk->markers[i].m.u_any.gcmarkbit) 7095 if (!mblk->markers[i].m.u_any.gcmarkbit)
7096 { 7096 {
7097 if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker) 7097 if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker)
7098 unchain_marker (&mblk->markers[i].m.u_marker); 7098 /* Make sure markers have been unchained from their buffer
7099 in sweep_buffer before we collect them. */
7100 eassert (!mblk->markers[i].m.u_marker.buffer);
7099 else if (mblk->markers[i].m.u_any.type == Lisp_Misc_Finalizer) 7101 else if (mblk->markers[i].m.u_any.type == Lisp_Misc_Finalizer)
7100 unchain_finalizer (&mblk->markers[i].m.u_finalizer); 7102 unchain_finalizer (&mblk->markers[i].m.u_finalizer);
7101#ifdef HAVE_MODULES 7103#ifdef HAVE_MODULES
@@ -7142,6 +7144,23 @@ sweep_misc (void)
7142 total_free_markers = num_free; 7144 total_free_markers = num_free;
7143} 7145}
7144 7146
7147/* Remove BUFFER's markers that are due to be swept. This is needed since
7148 we treat BUF_MARKERS and markers's `next' field as weak pointers. */
7149static void
7150unchain_dead_markers (struct buffer *buffer)
7151{
7152 struct Lisp_Marker *this, **prev = &BUF_MARKERS (buffer);
7153
7154 while ((this = *prev))
7155 if (this->gcmarkbit)
7156 prev = &this->next;
7157 else
7158 {
7159 this->buffer = NULL;
7160 *prev = this->next;
7161 }
7162}
7163
7145NO_INLINE /* For better stack traces */ 7164NO_INLINE /* For better stack traces */
7146static void 7165static void
7147sweep_buffers (void) 7166sweep_buffers (void)
@@ -7160,6 +7179,7 @@ sweep_buffers (void)
7160 VECTOR_UNMARK (buffer); 7179 VECTOR_UNMARK (buffer);
7161 /* Do not use buffer_(set|get)_intervals here. */ 7180 /* Do not use buffer_(set|get)_intervals here. */
7162 buffer->text->intervals = balance_intervals (buffer->text->intervals); 7181 buffer->text->intervals = balance_intervals (buffer->text->intervals);
7182 unchain_dead_markers (buffer);
7163 total_buffers++; 7183 total_buffers++;
7164 bprev = &buffer->next; 7184 bprev = &buffer->next;
7165 } 7185 }
@@ -7179,8 +7199,8 @@ gc_sweep (void)
7179 sweep_floats (); 7199 sweep_floats ();
7180 sweep_intervals (); 7200 sweep_intervals ();
7181 sweep_symbols (); 7201 sweep_symbols ();
7182 sweep_misc ();
7183 sweep_buffers (); 7202 sweep_buffers ();
7203 sweep_misc ();
7184 sweep_vectors (); 7204 sweep_vectors ();
7185 check_string_bytes (!noninteractive); 7205 check_string_bytes (!noninteractive);
7186} 7206}