aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2019-05-15 10:26:54 -0700
committerPaul Eggert2019-05-15 10:27:55 -0700
commitd4868b2bee88c89e704b4228a34e29dfc4a9f2a5 (patch)
tree716b52af67c7f615c39dc3634454feb3e6dcc400
parent32b01c02b48963a242fcc984c3599f59e59c1b2c (diff)
downloademacs-d4868b2bee88c89e704b4228a34e29dfc4a9f2a5.tar.gz
emacs-d4868b2bee88c89e704b4228a34e29dfc4a9f2a5.zip
Tune reading of radix integers
This improves the performance of (read "%xFF") by about 25% on my platform. * src/lread.c: Include <vla.h>, so that we can better document buffer sizes of arguments. (invalid_radix_integer_format, stackbufsize): New constants. (free_contents): Remove. All uses removed. (invalid_radix_integer): New function. (read_integer): New arg STACKBUF. Assume radix is in range. All uses changed. Use STACKBUF to avoid calling malloc in the usual case. Use grow_read_buffer to simplify. (read1): Tune. Improve quality of diagnostic when MOST_POSITIVE_FIXNUM < radix <= EMACS_INT_MAX.
-rw-r--r--src/lread.c147
1 files changed, 73 insertions, 74 deletions
diff --git a/src/lread.c b/src/lread.c
index c37719e0d24..5fa90cad3f3 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -44,6 +44,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
44#include "blockinput.h" 44#include "blockinput.h"
45#include "pdumper.h" 45#include "pdumper.h"
46#include <c-ctype.h> 46#include <c-ctype.h>
47#include <vla.h>
47 48
48#ifdef MSDOS 49#ifdef MSDOS
49#include "msdos.h" 50#include "msdos.h"
@@ -2640,89 +2641,83 @@ digit_to_number (int character, int base)
2640 return digit < base ? digit : -1; 2641 return digit < base ? digit : -1;
2641} 2642}
2642 2643
2644static char const invalid_radix_integer_format[] = "integer, radix %"pI"d";
2645
2646/* Small, as read1 is recursive (Bug#31995). But big enough to hold
2647 the invalid_radix_integer string. */
2648enum { stackbufsize = max (64,
2649 (sizeof invalid_radix_integer_format
2650 - sizeof "%"pI"d"
2651 + INT_STRLEN_BOUND (EMACS_INT) + 1)) };
2652
2643static void 2653static void
2644free_contents (void *p) 2654invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)])
2645{ 2655{
2646 void **ptr = (void **) p; 2656 sprintf (stackbuf, invalid_radix_integer_format, radix);
2647 xfree (*ptr); 2657 invalid_syntax (stackbuf);
2648} 2658}
2649 2659
2650/* Read an integer in radix RADIX using READCHARFUN to read 2660/* Read an integer in radix RADIX using READCHARFUN to read
2651 characters. RADIX must be in the interval [2..36]; if it isn't, a 2661 characters. RADIX must be in the interval [2..36]. Use STACKBUF
2652 read error is signaled . Value is the integer read. Signals an 2662 for temporary storage as needed. Value is the integer read.
2653 error if encountering invalid read syntax or if RADIX is out of 2663 Signal an error if encountering invalid read syntax. */
2654 range. */
2655 2664
2656static Lisp_Object 2665static Lisp_Object
2657read_integer (Lisp_Object readcharfun, EMACS_INT radix) 2666read_integer (Lisp_Object readcharfun, int radix,
2667 char stackbuf[VLA_ELEMS (stackbufsize)])
2658{ 2668{
2659 /* Room for sign, leading 0, other digits, trailing NUL byte. 2669 char *read_buffer = stackbuf;
2660 Also, room for invalid syntax diagnostic. */ 2670 ptrdiff_t read_buffer_size = stackbufsize;
2661 size_t len = max (1 + 1 + UINTMAX_WIDTH + 1, 2671 char *p = read_buffer;
2662 sizeof "integer, radix " + INT_STRLEN_BOUND (EMACS_INT)); 2672 char *heapbuf = NULL;
2663 char *buf = xmalloc (len);
2664 char *p = buf;
2665 int valid = -1; /* 1 if valid, 0 if not, -1 if incomplete. */ 2673 int valid = -1; /* 1 if valid, 0 if not, -1 if incomplete. */
2666
2667 ptrdiff_t count = SPECPDL_INDEX (); 2674 ptrdiff_t count = SPECPDL_INDEX ();
2668 record_unwind_protect_ptr (free_contents, &buf);
2669 2675
2670 if (radix < 2 || radix > 36) 2676 int c = READCHAR;
2671 valid = 0; 2677 if (c == '-' || c == '+')
2672 else
2673 { 2678 {
2674 int c, digit; 2679 *p++ = c;
2675
2676 p = buf;
2677
2678 c = READCHAR; 2680 c = READCHAR;
2679 if (c == '-' || c == '+') 2681 }
2680 {
2681 *p++ = c;
2682 c = READCHAR;
2683 }
2684 2682
2685 if (c == '0') 2683 if (c == '0')
2686 { 2684 {
2687 *p++ = c; 2685 *p++ = c;
2688 valid = 1; 2686 valid = 1;
2689 2687
2690 /* Ignore redundant leading zeros, so the buffer doesn't 2688 /* Ignore redundant leading zeros, so the buffer doesn't
2691 fill up with them. */ 2689 fill up with them. */
2692 do 2690 do
2693 c = READCHAR; 2691 c = READCHAR;
2694 while (c == '0'); 2692 while (c == '0');
2695 } 2693 }
2696 2694
2697 while ((digit = digit_to_number (c, radix)) >= -1) 2695 for (int digit; (digit = digit_to_number (c, radix)) >= -1; )
2696 {
2697 if (digit == -1)
2698 valid = 0;
2699 if (valid < 0)
2700 valid = 1;
2701 /* Allow 1 extra byte for the \0. */
2702 if (p + 1 == read_buffer + read_buffer_size)
2698 { 2703 {
2699 if (digit == -1) 2704 ptrdiff_t offset = p - read_buffer;
2700 valid = 0; 2705 read_buffer = grow_read_buffer (read_buffer, offset,
2701 if (valid < 0) 2706 &heapbuf, &read_buffer_size,
2702 valid = 1; 2707 count);
2703 /* Allow 1 extra byte for the \0. */ 2708 p = read_buffer + offset;
2704 if (p + 1 == buf + len)
2705 {
2706 ptrdiff_t where = p - buf;
2707 len *= 2;
2708 buf = xrealloc (buf, len);
2709 p = buf + where;
2710 }
2711 *p++ = c;
2712 c = READCHAR;
2713 } 2709 }
2714 2710 *p++ = c;
2715 UNREAD (c); 2711 c = READCHAR;
2716 } 2712 }
2717 2713
2714 UNREAD (c);
2715
2718 if (valid != 1) 2716 if (valid != 1)
2719 { 2717 invalid_radix_integer (radix, stackbuf);
2720 sprintf (buf, "integer, radix %"pI"d", radix);
2721 invalid_syntax (buf);
2722 }
2723 2718
2724 *p = '\0'; 2719 *p = '\0';
2725 return unbind_to (count, string_to_number (buf, radix, 0)); 2720 return unbind_to (count, string_to_number (read_buffer, radix, NULL));
2726} 2721}
2727 2722
2728 2723
@@ -2738,7 +2733,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2738 int c; 2733 int c;
2739 bool uninterned_symbol = false; 2734 bool uninterned_symbol = false;
2740 bool multibyte; 2735 bool multibyte;
2741 char stackbuf[128]; /* Small, as read1 is recursive (Bug#31995). */ 2736 char stackbuf[stackbufsize];
2742 current_thread->stack_top = stackbuf; 2737 current_thread->stack_top = stackbuf;
2743 2738
2744 *pch = 0; 2739 *pch = 0;
@@ -3108,30 +3103,34 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3108 /* ## is the empty symbol. */ 3103 /* ## is the empty symbol. */
3109 if (c == '#') 3104 if (c == '#')
3110 return Fintern (empty_unibyte_string, Qnil); 3105 return Fintern (empty_unibyte_string, Qnil);
3111 /* Reader forms that can reuse previously read objects. */ 3106
3112 if (c >= '0' && c <= '9') 3107 if (c >= '0' && c <= '9')
3113 { 3108 {
3114 EMACS_INT n = 0; 3109 EMACS_INT n = c - '0';
3115 Lisp_Object tem;
3116 bool overflow = false; 3110 bool overflow = false;
3117 3111
3118 /* Read a non-negative integer. */ 3112 /* Read a non-negative integer. */
3119 while (c >= '0' && c <= '9') 3113 while ('0' <= (c = READCHAR) && c <= '9')
3120 { 3114 {
3121 overflow |= INT_MULTIPLY_WRAPV (n, 10, &n); 3115 overflow |= INT_MULTIPLY_WRAPV (n, 10, &n);
3122 overflow |= INT_ADD_WRAPV (n, c - '0', &n); 3116 overflow |= INT_ADD_WRAPV (n, c - '0', &n);
3123 c = READCHAR;
3124 } 3117 }
3125 3118
3126 if (!overflow && n <= MOST_POSITIVE_FIXNUM) 3119 if (!overflow)
3127 { 3120 {
3128 if (c == 'r' || c == 'R') 3121 if (c == 'r' || c == 'R')
3129 return read_integer (readcharfun, n); 3122 {
3123 if (! (2 <= n && n <= 36))
3124 invalid_radix_integer (n, stackbuf);
3125 return read_integer (readcharfun, n, stackbuf);
3126 }
3130 3127
3131 if (! NILP (Vread_circle)) 3128 if (n <= MOST_POSITIVE_FIXNUM && ! NILP (Vread_circle))
3132 { 3129 {
3130 /* Reader forms that can reuse previously read objects. */
3131
3133 /* #n=object returns object, but associates it with 3132 /* #n=object returns object, but associates it with
3134 n for #n#. */ 3133 n for #n#. */
3135 if (c == '=') 3134 if (c == '=')
3136 { 3135 {
3137 /* Make a placeholder for #n# to use temporarily. */ 3136 /* Make a placeholder for #n# to use temporarily. */
@@ -3160,7 +3159,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3160 hash_put (h, number, placeholder, hash); 3159 hash_put (h, number, placeholder, hash);
3161 3160
3162 /* Read the object itself. */ 3161 /* Read the object itself. */
3163 tem = read0 (readcharfun); 3162 Lisp_Object tem = read0 (readcharfun);
3164 3163
3165 /* If it can be recursive, remember it for 3164 /* If it can be recursive, remember it for
3166 future substitutions. */ 3165 future substitutions. */
@@ -3210,11 +3209,11 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3210 /* Fall through to error message. */ 3209 /* Fall through to error message. */
3211 } 3210 }
3212 else if (c == 'x' || c == 'X') 3211 else if (c == 'x' || c == 'X')
3213 return read_integer (readcharfun, 16); 3212 return read_integer (readcharfun, 16, stackbuf);
3214 else if (c == 'o' || c == 'O') 3213 else if (c == 'o' || c == 'O')
3215 return read_integer (readcharfun, 8); 3214 return read_integer (readcharfun, 8, stackbuf);
3216 else if (c == 'b' || c == 'B') 3215 else if (c == 'b' || c == 'B')
3217 return read_integer (readcharfun, 2); 3216 return read_integer (readcharfun, 2, stackbuf);
3218 3217
3219 UNREAD (c); 3218 UNREAD (c);
3220 invalid_syntax ("#"); 3219 invalid_syntax ("#");