aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2020-01-17 23:59:51 -0800
committerPaul Eggert2020-01-18 00:02:12 -0800
commitc1b6d5c5b9f8eee8aa3a8071292e8b3281ecf28a (patch)
treef484fd77b1eec8659d17531c39e1bff1301c5b33 /src
parentbce3d89a6042da8830199d912c3b26aefaf7288c (diff)
downloademacs-c1b6d5c5b9f8eee8aa3a8071292e8b3281ecf28a.tar.gz
emacs-c1b6d5c5b9f8eee8aa3a8071292e8b3281ecf28a.zip
Improve performance when a string's byte count changes
* src/alloc.c (allocate_string_data): Now static. Remove code for when Faset calls this function when S already has data assigned, as that can no longer happen. (resize_string_data): New function, which avoids relocation in more cases than the old code did, by not bothering to relocate when the size changes falls within the alignment slop. * src/data.c (Faset): Use resize_string_data. Change a while to a do-while since it must iterate at least once.
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c63
-rw-r--r--src/data.c36
-rw-r--r--src/lisp.h3
3 files changed, 57 insertions, 45 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 7eb37bb12da..9dc6ef79e39 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -1786,13 +1786,12 @@ allocate_string (void)
1786 1786
1787 If CLEARIT, also clear the other bytes of S->u.s.data. */ 1787 If CLEARIT, also clear the other bytes of S->u.s.data. */
1788 1788
1789void 1789static void
1790allocate_string_data (struct Lisp_String *s, 1790allocate_string_data (struct Lisp_String *s,
1791 EMACS_INT nchars, EMACS_INT nbytes, bool clearit) 1791 EMACS_INT nchars, EMACS_INT nbytes, bool clearit)
1792{ 1792{
1793 sdata *data, *old_data; 1793 sdata *data;
1794 struct sblock *b; 1794 struct sblock *b;
1795 ptrdiff_t old_nbytes;
1796 1795
1797 if (STRING_BYTES_MAX < nbytes) 1796 if (STRING_BYTES_MAX < nbytes)
1798 string_overflow (); 1797 string_overflow ();
@@ -1800,13 +1799,6 @@ allocate_string_data (struct Lisp_String *s,
1800 /* Determine the number of bytes needed to store NBYTES bytes 1799 /* Determine the number of bytes needed to store NBYTES bytes
1801 of string data. */ 1800 of string data. */
1802 ptrdiff_t needed = sdata_size (nbytes); 1801 ptrdiff_t needed = sdata_size (nbytes);
1803 if (s->u.s.data)
1804 {
1805 old_data = SDATA_OF_STRING (s);
1806 old_nbytes = STRING_BYTES (s);
1807 }
1808 else
1809 old_data = NULL;
1810 1802
1811 MALLOC_BLOCK_INPUT; 1803 MALLOC_BLOCK_INPUT;
1812 1804
@@ -1875,16 +1867,53 @@ allocate_string_data (struct Lisp_String *s,
1875 GC_STRING_OVERRUN_COOKIE_SIZE); 1867 GC_STRING_OVERRUN_COOKIE_SIZE);
1876#endif 1868#endif
1877 1869
1878 /* Note that Faset may call to this function when S has already data 1870 tally_consing (needed);
1879 assigned. In this case, mark data as free by setting it's string 1871}
1880 back-pointer to null, and record the size of the data in it. */ 1872
1881 if (old_data) 1873/* Reallocate the data for STRING when a single character is replaced.
1874 The character is at byte offset CIDX_BYTE in the string.
1875 The character being replaced is CLEN bytes long,
1876 and the character that will replace it is NEW_CLEN bytes long.
1877 Return the address of where the caller should store the
1878 the new character. */
1879
1880unsigned char *
1881resize_string_data (Lisp_Object string, ptrdiff_t cidx_byte,
1882 int clen, int new_clen)
1883{
1884 sdata *old_sdata = SDATA_OF_STRING (XSTRING (string));
1885 ptrdiff_t nchars = SCHARS (string);
1886 ptrdiff_t nbytes = SBYTES (string);
1887 ptrdiff_t new_nbytes = nbytes + (new_clen - clen);
1888 unsigned char *data = SDATA (string);
1889 unsigned char *new_charaddr;
1890
1891 if (sdata_size (nbytes) == sdata_size (new_nbytes))
1892 {
1893 /* No need to reallocate, as the size change falls within the
1894 alignment slop. */
1895 new_charaddr = data + cidx_byte;
1896 memmove (new_charaddr + new_clen, new_charaddr + clen,
1897 nbytes - (cidx_byte + (clen - 1)));
1898 }
1899 else
1882 { 1900 {
1883 SDATA_NBYTES (old_data) = old_nbytes; 1901 allocate_string_data (XSTRING (string), nchars, new_nbytes, false);
1884 old_data->string = NULL; 1902 unsigned char *new_data = SDATA (string);
1903 new_charaddr = new_data + cidx_byte;
1904 memcpy (new_charaddr + new_clen, data + cidx_byte + clen,
1905 nbytes - (cidx_byte + clen));
1906 memcpy (new_data, data, cidx_byte);
1907
1908 /* Mark old string data as free by setting its string back-pointer
1909 to null, and record the size of the data in it. */
1910 SDATA_NBYTES (old_sdata) = nbytes;
1911 old_sdata->string = NULL;
1885 } 1912 }
1886 1913
1887 tally_consing (needed); 1914 clear_string_char_byte_cache ();
1915
1916 return new_charaddr;
1888} 1917}
1889 1918
1890 1919
diff --git a/src/data.c b/src/data.c
index c8445e7d874..cd7db6a0bb9 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2303,34 +2303,18 @@ bool-vector. IDX starts at 0. */)
2303 2303
2304 if (STRING_MULTIBYTE (array)) 2304 if (STRING_MULTIBYTE (array))
2305 { 2305 {
2306 ptrdiff_t idxval_byte, nbytes; 2306 unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf;
2307 int prev_bytes, new_bytes; 2307 ptrdiff_t idxval_byte = string_char_to_byte (array, idxval);
2308 unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf, *p1; 2308 unsigned char *p1 = SDATA (array) + idxval_byte;
2309 2309
2310 nbytes = SBYTES (array); 2310 int prev_bytes = BYTES_BY_CHAR_HEAD (*p1);
2311 idxval_byte = string_char_to_byte (array, idxval); 2311 int new_bytes = CHAR_STRING (c, p0);
2312 p1 = SDATA (array) + idxval_byte;
2313 prev_bytes = BYTES_BY_CHAR_HEAD (*p1);
2314 new_bytes = CHAR_STRING (c, p0);
2315 if (prev_bytes != new_bytes) 2312 if (prev_bytes != new_bytes)
2316 { 2313 p1 = resize_string_data (array, idxval_byte, prev_bytes, new_bytes);
2317 /* We must relocate the string data. */ 2314
2318 ptrdiff_t nchars = SCHARS (array); 2315 do
2319 USE_SAFE_ALLOCA;
2320 unsigned char *str = SAFE_ALLOCA (nbytes);
2321
2322 memcpy (str, SDATA (array), nbytes);
2323 allocate_string_data (XSTRING (array), nchars,
2324 nbytes + new_bytes - prev_bytes, false);
2325 memcpy (SDATA (array), str, idxval_byte);
2326 p1 = SDATA (array) + idxval_byte;
2327 memcpy (p1 + new_bytes, str + idxval_byte + prev_bytes,
2328 nbytes - (idxval_byte + prev_bytes));
2329 SAFE_FREE ();
2330 clear_string_char_byte_cache ();
2331 }
2332 while (new_bytes--)
2333 *p1++ = *p0++; 2316 *p1++ = *p0++;
2317 while (--new_bytes != 0);
2334 } 2318 }
2335 else 2319 else
2336 { 2320 {
diff --git a/src/lisp.h b/src/lisp.h
index 3681b7b2a7c..4bcd1228443 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3812,8 +3812,7 @@ extern void parse_str_as_multibyte (const unsigned char *, ptrdiff_t,
3812/* Defined in alloc.c. */ 3812/* Defined in alloc.c. */
3813extern void *my_heap_start (void); 3813extern void *my_heap_start (void);
3814extern void check_pure_size (void); 3814extern void check_pure_size (void);
3815extern void allocate_string_data (struct Lisp_String *, EMACS_INT, EMACS_INT, 3815unsigned char *resize_string_data (Lisp_Object, ptrdiff_t, int, int);
3816 bool);
3817extern void malloc_warning (const char *); 3816extern void malloc_warning (const char *);
3818extern AVOID memory_full (size_t); 3817extern AVOID memory_full (size_t);
3819extern AVOID buffer_memory_full (ptrdiff_t); 3818extern AVOID buffer_memory_full (ptrdiff_t);