diff options
| author | Paul Eggert | 2020-08-24 13:12:51 -0700 |
|---|---|---|
| committer | Paul Eggert | 2020-08-25 11:25:21 -0700 |
| commit | eb77572257bfa4e649c0c8852d2d0a58ad63eaa5 (patch) | |
| tree | de34a3b16d789fd51d61a8c0e0036fe91ed4196c /src | |
| parent | a142bbd288a814822ba63194c690552f8c0ce425 (diff) | |
| download | emacs-eb77572257bfa4e649c0c8852d2d0a58ad63eaa5.tar.gz emacs-eb77572257bfa4e649c0c8852d2d0a58ad63eaa5.zip | |
Fix replace-region-contents performance bug
Backport from master.
* src/editfns.c (rbc_quitcounter): Remove; the quitcounter
is now part of the context.
(EXTRA_CONTEXT_FIELDS): Remove unused member early_abort_tests.
Add jmp, quitcounter.
(Freplace_buffer_contents): Use setjmp/longjmp to recover from
a compareseq that runs too long. Omit unnecessary rarely_quit
call.
(buffer_chars_equal): Occasionally check for early abort and
longjmp out if so (Bug#43016).
Diffstat (limited to 'src')
| -rw-r--r-- | src/editfns.c | 31 |
1 files changed, 15 insertions, 16 deletions
diff --git a/src/editfns.c b/src/editfns.c index fe1feaf1e77..f660513b2a4 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -1913,9 +1913,6 @@ determines whether case is significant or ignored. */) | |||
| 1913 | #undef EQUAL | 1913 | #undef EQUAL |
| 1914 | #define USE_HEURISTIC | 1914 | #define USE_HEURISTIC |
| 1915 | 1915 | ||
| 1916 | /* Counter used to rarely_quit in replace-buffer-contents. */ | ||
| 1917 | static unsigned short rbc_quitcounter; | ||
| 1918 | |||
| 1919 | #define XVECREF_YVECREF_EQUAL(ctx, xoff, yoff) \ | 1916 | #define XVECREF_YVECREF_EQUAL(ctx, xoff, yoff) \ |
| 1920 | buffer_chars_equal ((ctx), (xoff), (yoff)) | 1917 | buffer_chars_equal ((ctx), (xoff), (yoff)) |
| 1921 | 1918 | ||
| @@ -1936,7 +1933,8 @@ static unsigned short rbc_quitcounter; | |||
| 1936 | unsigned char *deletions; \ | 1933 | unsigned char *deletions; \ |
| 1937 | unsigned char *insertions; \ | 1934 | unsigned char *insertions; \ |
| 1938 | struct timespec time_limit; \ | 1935 | struct timespec time_limit; \ |
| 1939 | unsigned int early_abort_tests; | 1936 | sys_jmp_buf jmp; \ |
| 1937 | unsigned short quitcounter; | ||
| 1940 | 1938 | ||
| 1941 | #define NOTE_DELETE(ctx, xoff) set_bit ((ctx)->deletions, (xoff)) | 1939 | #define NOTE_DELETE(ctx, xoff) set_bit ((ctx)->deletions, (xoff)) |
| 1942 | #define NOTE_INSERT(ctx, yoff) set_bit ((ctx)->insertions, (yoff)) | 1940 | #define NOTE_INSERT(ctx, yoff) set_bit ((ctx)->insertions, (yoff)) |
| @@ -2065,14 +2063,17 @@ nil. */) | |||
| 2065 | .heuristic = true, | 2063 | .heuristic = true, |
| 2066 | .too_expensive = XFIXNUM (max_costs), | 2064 | .too_expensive = XFIXNUM (max_costs), |
| 2067 | .time_limit = time_limit, | 2065 | .time_limit = time_limit, |
| 2068 | .early_abort_tests = 0 | ||
| 2069 | }; | 2066 | }; |
| 2070 | memclear (ctx.deletions, del_bytes); | 2067 | memclear (ctx.deletions, del_bytes); |
| 2071 | memclear (ctx.insertions, ins_bytes); | 2068 | memclear (ctx.insertions, ins_bytes); |
| 2072 | 2069 | ||
| 2073 | /* compareseq requires indices to be zero-based. We add BEGV back | 2070 | /* compareseq requires indices to be zero-based. We add BEGV back |
| 2074 | later. */ | 2071 | later. */ |
| 2075 | bool early_abort = compareseq (0, size_a, 0, size_b, false, &ctx); | 2072 | bool early_abort; |
| 2073 | if (! sys_setjmp (ctx.jmp)) | ||
| 2074 | early_abort = compareseq (0, size_a, 0, size_b, false, &ctx); | ||
| 2075 | else | ||
| 2076 | early_abort = true; | ||
| 2076 | 2077 | ||
| 2077 | if (early_abort) | 2078 | if (early_abort) |
| 2078 | { | 2079 | { |
| @@ -2082,8 +2083,6 @@ nil. */) | |||
| 2082 | return Qnil; | 2083 | return Qnil; |
| 2083 | } | 2084 | } |
| 2084 | 2085 | ||
| 2085 | rbc_quitcounter = 0; | ||
| 2086 | |||
| 2087 | Fundo_boundary (); | 2086 | Fundo_boundary (); |
| 2088 | bool modification_hooks_inhibited = false; | 2087 | bool modification_hooks_inhibited = false; |
| 2089 | record_unwind_protect_excursion (); | 2088 | record_unwind_protect_excursion (); |
| @@ -2107,8 +2106,7 @@ nil. */) | |||
| 2107 | walk backwards, we don’t have to keep the positions in sync. */ | 2106 | walk backwards, we don’t have to keep the positions in sync. */ |
| 2108 | while (i >= 0 || j >= 0) | 2107 | while (i >= 0 || j >= 0) |
| 2109 | { | 2108 | { |
| 2110 | /* Allow the user to quit if this gets too slow. */ | 2109 | rarely_quit (++ctx.quitcounter); |
| 2111 | rarely_quit (++rbc_quitcounter); | ||
| 2112 | 2110 | ||
| 2113 | /* Check whether there is a change (insertion or deletion) | 2111 | /* Check whether there is a change (insertion or deletion) |
| 2114 | before the current position. */ | 2112 | before the current position. */ |
| @@ -2123,8 +2121,6 @@ nil. */) | |||
| 2123 | while (j > 0 && bit_is_set (ctx.insertions, j - 1)) | 2121 | while (j > 0 && bit_is_set (ctx.insertions, j - 1)) |
| 2124 | --j; | 2122 | --j; |
| 2125 | 2123 | ||
| 2126 | rarely_quit (rbc_quitcounter++); | ||
| 2127 | |||
| 2128 | ptrdiff_t beg_a = min_a + i; | 2124 | ptrdiff_t beg_a = min_a + i; |
| 2129 | ptrdiff_t beg_b = min_b + j; | 2125 | ptrdiff_t beg_b = min_b + j; |
| 2130 | eassert (beg_a <= end_a); | 2126 | eassert (beg_a <= end_a); |
| @@ -2144,7 +2140,6 @@ nil. */) | |||
| 2144 | } | 2140 | } |
| 2145 | 2141 | ||
| 2146 | SAFE_FREE_UNBIND_TO (count, Qnil); | 2142 | SAFE_FREE_UNBIND_TO (count, Qnil); |
| 2147 | rbc_quitcounter = 0; | ||
| 2148 | 2143 | ||
| 2149 | if (modification_hooks_inhibited) | 2144 | if (modification_hooks_inhibited) |
| 2150 | { | 2145 | { |
| @@ -2191,12 +2186,16 @@ static bool | |||
| 2191 | buffer_chars_equal (struct context *ctx, | 2186 | buffer_chars_equal (struct context *ctx, |
| 2192 | ptrdiff_t pos_a, ptrdiff_t pos_b) | 2187 | ptrdiff_t pos_a, ptrdiff_t pos_b) |
| 2193 | { | 2188 | { |
| 2189 | if (!++ctx->quitcounter) | ||
| 2190 | { | ||
| 2191 | maybe_quit (); | ||
| 2192 | if (compareseq_early_abort (ctx)) | ||
| 2193 | sys_longjmp (ctx->jmp, 1); | ||
| 2194 | } | ||
| 2195 | |||
| 2194 | pos_a += ctx->beg_a; | 2196 | pos_a += ctx->beg_a; |
| 2195 | pos_b += ctx->beg_b; | 2197 | pos_b += ctx->beg_b; |
| 2196 | 2198 | ||
| 2197 | /* Allow the user to escape out of a slow compareseq call. */ | ||
| 2198 | rarely_quit (++rbc_quitcounter); | ||
| 2199 | |||
| 2200 | ptrdiff_t bpos_a = | 2199 | ptrdiff_t bpos_a = |
| 2201 | ctx->a_unibyte ? pos_a : buf_charpos_to_bytepos (ctx->buffer_a, pos_a); | 2200 | ctx->a_unibyte ? pos_a : buf_charpos_to_bytepos (ctx->buffer_a, pos_a); |
| 2202 | ptrdiff_t bpos_b = | 2201 | ptrdiff_t bpos_b = |