aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2020-08-24 13:12:51 -0700
committerPaul Eggert2020-08-24 13:17:48 -0700
commit08a6d14e4116c74284c12dd1319780afbcbbfd1d (patch)
tree811ed4b80a5dc493a9ffe25046005dcfea23ab96 /src
parent519fc10f121c59d6844afaf0ef0a1e1d67a2a934 (diff)
downloademacs-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.c31
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. */
1881static 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
2155buffer_chars_equal (struct context *ctx, 2150buffer_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 =