diff options
| author | Paul Eggert | 2020-08-24 13:12:51 -0700 |
|---|---|---|
| committer | Paul Eggert | 2020-08-24 13:17:48 -0700 |
| commit | 08a6d14e4116c74284c12dd1319780afbcbbfd1d (patch) | |
| tree | 811ed4b80a5dc493a9ffe25046005dcfea23ab96 /src | |
| parent | 519fc10f121c59d6844afaf0ef0a1e1d67a2a934 (diff) | |
| download | emacs-08a6d14e4116c74284c12dd1319780afbcbbfd1d.tar.gz emacs-08a6d14e4116c74284c12dd1319780afbcbbfd1d.zip | |
Fix replace-region-contents performance bug
* 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 949f3825a3c..a5368c59dad 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -1877,9 +1877,6 @@ determines whether case is significant or ignored. */) | |||
| 1877 | #undef EQUAL | 1877 | #undef EQUAL |
| 1878 | #define USE_HEURISTIC | 1878 | #define USE_HEURISTIC |
| 1879 | 1879 | ||
| 1880 | /* Counter used to rarely_quit in replace-buffer-contents. */ | ||
| 1881 | static unsigned short rbc_quitcounter; | ||
| 1882 | |||
| 1883 | #define XVECREF_YVECREF_EQUAL(ctx, xoff, yoff) \ | 1880 | #define XVECREF_YVECREF_EQUAL(ctx, xoff, yoff) \ |
| 1884 | buffer_chars_equal ((ctx), (xoff), (yoff)) | 1881 | buffer_chars_equal ((ctx), (xoff), (yoff)) |
| 1885 | 1882 | ||
| @@ -1900,7 +1897,8 @@ static unsigned short rbc_quitcounter; | |||
| 1900 | unsigned char *deletions; \ | 1897 | unsigned char *deletions; \ |
| 1901 | unsigned char *insertions; \ | 1898 | unsigned char *insertions; \ |
| 1902 | struct timespec time_limit; \ | 1899 | struct timespec time_limit; \ |
| 1903 | unsigned int early_abort_tests; | 1900 | sys_jmp_buf jmp; \ |
| 1901 | unsigned short quitcounter; | ||
| 1904 | 1902 | ||
| 1905 | #define NOTE_DELETE(ctx, xoff) set_bit ((ctx)->deletions, (xoff)) | 1903 | #define NOTE_DELETE(ctx, xoff) set_bit ((ctx)->deletions, (xoff)) |
| 1906 | #define NOTE_INSERT(ctx, yoff) set_bit ((ctx)->insertions, (yoff)) | 1904 | #define NOTE_INSERT(ctx, yoff) set_bit ((ctx)->insertions, (yoff)) |
| @@ -2029,14 +2027,17 @@ nil. */) | |||
| 2029 | .heuristic = true, | 2027 | .heuristic = true, |
| 2030 | .too_expensive = XFIXNUM (max_costs), | 2028 | .too_expensive = XFIXNUM (max_costs), |
| 2031 | .time_limit = time_limit, | 2029 | .time_limit = time_limit, |
| 2032 | .early_abort_tests = 0 | ||
| 2033 | }; | 2030 | }; |
| 2034 | memclear (ctx.deletions, del_bytes); | 2031 | memclear (ctx.deletions, del_bytes); |
| 2035 | memclear (ctx.insertions, ins_bytes); | 2032 | memclear (ctx.insertions, ins_bytes); |
| 2036 | 2033 | ||
| 2037 | /* compareseq requires indices to be zero-based. We add BEGV back | 2034 | /* compareseq requires indices to be zero-based. We add BEGV back |
| 2038 | later. */ | 2035 | later. */ |
| 2039 | bool early_abort = compareseq (0, size_a, 0, size_b, false, &ctx); | 2036 | bool early_abort; |
| 2037 | if (! sys_setjmp (ctx.jmp)) | ||
| 2038 | early_abort = compareseq (0, size_a, 0, size_b, false, &ctx); | ||
| 2039 | else | ||
| 2040 | early_abort = true; | ||
| 2040 | 2041 | ||
| 2041 | if (early_abort) | 2042 | if (early_abort) |
| 2042 | { | 2043 | { |
| @@ -2046,8 +2047,6 @@ nil. */) | |||
| 2046 | return Qnil; | 2047 | return Qnil; |
| 2047 | } | 2048 | } |
| 2048 | 2049 | ||
| 2049 | rbc_quitcounter = 0; | ||
| 2050 | |||
| 2051 | Fundo_boundary (); | 2050 | Fundo_boundary (); |
| 2052 | bool modification_hooks_inhibited = false; | 2051 | bool modification_hooks_inhibited = false; |
| 2053 | record_unwind_protect_excursion (); | 2052 | record_unwind_protect_excursion (); |
| @@ -2071,8 +2070,7 @@ nil. */) | |||
| 2071 | walk backwards, we don’t have to keep the positions in sync. */ | 2070 | walk backwards, we don’t have to keep the positions in sync. */ |
| 2072 | while (i >= 0 || j >= 0) | 2071 | while (i >= 0 || j >= 0) |
| 2073 | { | 2072 | { |
| 2074 | /* Allow the user to quit if this gets too slow. */ | 2073 | rarely_quit (++ctx.quitcounter); |
| 2075 | rarely_quit (++rbc_quitcounter); | ||
| 2076 | 2074 | ||
| 2077 | /* Check whether there is a change (insertion or deletion) | 2075 | /* Check whether there is a change (insertion or deletion) |
| 2078 | before the current position. */ | 2076 | before the current position. */ |
| @@ -2087,8 +2085,6 @@ nil. */) | |||
| 2087 | while (j > 0 && bit_is_set (ctx.insertions, j - 1)) | 2085 | while (j > 0 && bit_is_set (ctx.insertions, j - 1)) |
| 2088 | --j; | 2086 | --j; |
| 2089 | 2087 | ||
| 2090 | rarely_quit (rbc_quitcounter++); | ||
| 2091 | |||
| 2092 | ptrdiff_t beg_a = min_a + i; | 2088 | ptrdiff_t beg_a = min_a + i; |
| 2093 | ptrdiff_t beg_b = min_b + j; | 2089 | ptrdiff_t beg_b = min_b + j; |
| 2094 | eassert (beg_a <= end_a); | 2090 | eassert (beg_a <= end_a); |
| @@ -2108,7 +2104,6 @@ nil. */) | |||
| 2108 | } | 2104 | } |
| 2109 | 2105 | ||
| 2110 | SAFE_FREE_UNBIND_TO (count, Qnil); | 2106 | SAFE_FREE_UNBIND_TO (count, Qnil); |
| 2111 | rbc_quitcounter = 0; | ||
| 2112 | 2107 | ||
| 2113 | if (modification_hooks_inhibited) | 2108 | if (modification_hooks_inhibited) |
| 2114 | { | 2109 | { |
| @@ -2155,12 +2150,16 @@ static bool | |||
| 2155 | buffer_chars_equal (struct context *ctx, | 2150 | buffer_chars_equal (struct context *ctx, |
| 2156 | ptrdiff_t pos_a, ptrdiff_t pos_b) | 2151 | ptrdiff_t pos_a, ptrdiff_t pos_b) |
| 2157 | { | 2152 | { |
| 2153 | if (!++ctx->quitcounter) | ||
| 2154 | { | ||
| 2155 | maybe_quit (); | ||
| 2156 | if (compareseq_early_abort (ctx)) | ||
| 2157 | sys_longjmp (ctx->jmp, 1); | ||
| 2158 | } | ||
| 2159 | |||
| 2158 | pos_a += ctx->beg_a; | 2160 | pos_a += ctx->beg_a; |
| 2159 | pos_b += ctx->beg_b; | 2161 | pos_b += ctx->beg_b; |
| 2160 | 2162 | ||
| 2161 | /* Allow the user to escape out of a slow compareseq call. */ | ||
| 2162 | rarely_quit (++rbc_quitcounter); | ||
| 2163 | |||
| 2164 | ptrdiff_t bpos_a = | 2163 | ptrdiff_t bpos_a = |
| 2165 | ctx->a_unibyte ? pos_a : buf_charpos_to_bytepos (ctx->buffer_a, pos_a); | 2164 | ctx->a_unibyte ? pos_a : buf_charpos_to_bytepos (ctx->buffer_a, pos_a); |
| 2166 | ptrdiff_t bpos_b = | 2165 | ptrdiff_t bpos_b = |