diff options
| author | Paul Eggert | 2020-01-17 23:59:51 -0800 |
|---|---|---|
| committer | Paul Eggert | 2020-01-18 00:02:12 -0800 |
| commit | c1b6d5c5b9f8eee8aa3a8071292e8b3281ecf28a (patch) | |
| tree | f484fd77b1eec8659d17531c39e1bff1301c5b33 /src | |
| parent | bce3d89a6042da8830199d912c3b26aefaf7288c (diff) | |
| download | emacs-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.c | 63 | ||||
| -rw-r--r-- | src/data.c | 36 | ||||
| -rw-r--r-- | src/lisp.h | 3 |
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 | ||
| 1789 | void | 1789 | static void |
| 1790 | allocate_string_data (struct Lisp_String *s, | 1790 | allocate_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 | |||
| 1880 | unsigned char * | ||
| 1881 | resize_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. */ |
| 3813 | extern void *my_heap_start (void); | 3813 | extern void *my_heap_start (void); |
| 3814 | extern void check_pure_size (void); | 3814 | extern void check_pure_size (void); |
| 3815 | extern void allocate_string_data (struct Lisp_String *, EMACS_INT, EMACS_INT, | 3815 | unsigned char *resize_string_data (Lisp_Object, ptrdiff_t, int, int); |
| 3816 | bool); | ||
| 3817 | extern void malloc_warning (const char *); | 3816 | extern void malloc_warning (const char *); |
| 3818 | extern AVOID memory_full (size_t); | 3817 | extern AVOID memory_full (size_t); |
| 3819 | extern AVOID buffer_memory_full (ptrdiff_t); | 3818 | extern AVOID buffer_memory_full (ptrdiff_t); |