diff options
| author | Stefan Monnier | 2018-03-23 11:09:54 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2018-03-23 11:09:54 -0400 |
| commit | cf3164523b32f01dbaad2c1364ecf2dcf8f22aa5 (patch) | |
| tree | 9dca9f6732e7b55b0285af36ff2de87919d4dde9 | |
| parent | 6695c1be51bd8a1e208ae02505b2a6fa64c85e68 (diff) | |
| download | emacs-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.c | 24 |
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. */ | ||
| 7149 | static void | ||
| 7150 | unchain_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 | |||
| 7145 | NO_INLINE /* For better stack traces */ | 7164 | NO_INLINE /* For better stack traces */ |
| 7146 | static void | 7165 | static void |
| 7147 | sweep_buffers (void) | 7166 | sweep_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 | } |