aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKen Raeburn2017-06-21 22:45:14 -0400
committerKen Raeburn2017-06-21 22:46:10 -0400
commit85f6aa33f55da97b13b5e81616f16a517d24f3d5 (patch)
tree76533b2a92306346ac591e93f52555a0708ac5dc /src
parent87a44b934ccecd2d9bdbf0afad576333741075b6 (diff)
parent59f3c86659c061e2673eb0da0bc78528d30f8f76 (diff)
downloademacs-85f6aa33f55da97b13b5e81616f16a517d24f3d5.tar.gz
emacs-85f6aa33f55da97b13b5e81616f16a517d24f3d5.zip
Merge several Lisp reader speedups.
Diffstat (limited to 'src')
-rw-r--r--src/charset.c14
-rw-r--r--src/lread.c221
2 files changed, 187 insertions, 48 deletions
diff --git a/src/charset.c b/src/charset.c
index f0b41400843..9d15375dd79 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -198,6 +198,10 @@ static struct
198 198
199#define GET_TEMP_CHARSET_WORK_DECODER(CODE) \ 199#define GET_TEMP_CHARSET_WORK_DECODER(CODE) \
200 (temp_charset_work->table.decoder[(CODE)]) 200 (temp_charset_work->table.decoder[(CODE)])
201
202#ifndef HAVE_GETC_UNLOCKED
203#define getc_unlocked getc
204#endif
201 205
202 206
203/* Set to 1 to warn that a charset map is loaded and thus a buffer 207/* Set to 1 to warn that a charset map is loaded and thus a buffer
@@ -416,15 +420,15 @@ read_hex (FILE *fp, bool *eof, bool *overflow)
416 int c; 420 int c;
417 unsigned n; 421 unsigned n;
418 422
419 while ((c = getc (fp)) != EOF) 423 while ((c = getc_unlocked (fp)) != EOF)
420 { 424 {
421 if (c == '#') 425 if (c == '#')
422 { 426 {
423 while ((c = getc (fp)) != EOF && c != '\n'); 427 while ((c = getc_unlocked (fp)) != EOF && c != '\n');
424 } 428 }
425 else if (c == '0') 429 else if (c == '0')
426 { 430 {
427 if ((c = getc (fp)) == EOF || c == 'x') 431 if ((c = getc_unlocked (fp)) == EOF || c == 'x')
428 break; 432 break;
429 } 433 }
430 } 434 }
@@ -434,7 +438,7 @@ read_hex (FILE *fp, bool *eof, bool *overflow)
434 return 0; 438 return 0;
435 } 439 }
436 n = 0; 440 n = 0;
437 while (c_isxdigit (c = getc (fp))) 441 while (c_isxdigit (c = getc_unlocked (fp)))
438 { 442 {
439 if (INT_LEFT_SHIFT_OVERFLOW (n, 4)) 443 if (INT_LEFT_SHIFT_OVERFLOW (n, 4))
440 *overflow = 1; 444 *overflow = 1;
@@ -508,7 +512,7 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile,
508 from = read_hex (fp, &eof, &overflow); 512 from = read_hex (fp, &eof, &overflow);
509 if (eof) 513 if (eof)
510 break; 514 break;
511 if (getc (fp) == '-') 515 if (getc_unlocked (fp) == '-')
512 to = read_hex (fp, &eof, &overflow); 516 to = read_hex (fp, &eof, &overflow);
513 else 517 else
514 to = from; 518 to = from;
diff --git a/src/lread.c b/src/lread.c
index 88dbc23b964..b01cbd5c072 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -72,11 +72,40 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
72#define file_tell ftell 72#define file_tell ftell
73#endif 73#endif
74 74
75/* The association list of objects read with the #n=object form. 75#ifndef HAVE_GETC_UNLOCKED
76 Each member of the list has the form (n . object), and is used to 76#define getc_unlocked getc
77 look up the object for the corresponding #n# construct. 77#endif
78 It must be set to nil before all top-level calls to read0. */ 78
79static Lisp_Object read_objects; 79/* The objects or placeholders read with the #n=object form.
80
81 A hash table maps a number to either a placeholder (while the
82 object is still being parsed, in case it's referenced within its
83 own definition) or to the completed object. With small integers
84 for keys, it's effectively little more than a vector, but it'll
85 manage any needed resizing for us.
86
87 The variable must be reset to an empty hash table before all
88 top-level calls to read0. In between calls, it may be an empty
89 hash table left unused from the previous call (to reduce
90 allocations), or nil. */
91static Lisp_Object read_objects_map;
92
93/* The recursive objects read with the #n=object form.
94
95 Objects that might have circular references are stored here, so
96 that recursive substitution knows not to keep processing them
97 multiple times.
98
99 Only objects that are completely processed, including substituting
100 references to themselves (but not necessarily replacing
101 placeholders for other objects still being read), are stored.
102
103 A hash table is used for efficient lookups of keys. We don't care
104 what the value slots hold. The variable must be set to an empty
105 hash table before all top-level calls to read0. In between calls,
106 it may be an empty hash table left unused from the previous call
107 (to reduce allocations), or nil. */
108static Lisp_Object read_objects_completed;
80 109
81/* File for get_file_char to read from. Use by load. */ 110/* File for get_file_char to read from. Use by load. */
82static FILE *instream; 111static FILE *instream;
@@ -445,7 +474,7 @@ readbyte_from_file (int c, Lisp_Object readcharfun)
445 } 474 }
446 475
447 block_input (); 476 block_input ();
448 c = getc (instream); 477 c = getc_unlocked (instream);
449 478
450 /* Interrupted reads have been observed while reading over the network. */ 479 /* Interrupted reads have been observed while reading over the network. */
451 while (c == EOF && ferror (instream) && errno == EINTR) 480 while (c == EOF && ferror (instream) && errno == EINTR)
@@ -454,7 +483,7 @@ readbyte_from_file (int c, Lisp_Object readcharfun)
454 maybe_quit (); 483 maybe_quit ();
455 block_input (); 484 block_input ();
456 clearerr (instream); 485 clearerr (instream);
457 c = getc (instream); 486 c = getc_unlocked (instream);
458 } 487 }
459 488
460 unblock_input (); 489 unblock_input ();
@@ -757,7 +786,7 @@ DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
757{ 786{
758 register Lisp_Object val; 787 register Lisp_Object val;
759 block_input (); 788 block_input ();
760 XSETINT (val, getc (instream)); 789 XSETINT (val, getc_unlocked (instream));
761 unblock_input (); 790 unblock_input ();
762 return val; 791 return val;
763} 792}
@@ -1908,6 +1937,18 @@ readevalloop (Lisp_Object readcharfun,
1908 || c == NO_BREAK_SPACE) 1937 || c == NO_BREAK_SPACE)
1909 goto read_next; 1938 goto read_next;
1910 1939
1940 if (! HASH_TABLE_P (read_objects_map)
1941 || XHASH_TABLE (read_objects_map)->count)
1942 read_objects_map
1943 = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
1944 DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
1945 Qnil, Qnil);
1946 if (! HASH_TABLE_P (read_objects_completed)
1947 || XHASH_TABLE (read_objects_completed)->count)
1948 read_objects_completed
1949 = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
1950 DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
1951 Qnil, Qnil);
1911 if (!NILP (Vpurify_flag) && c == '(') 1952 if (!NILP (Vpurify_flag) && c == '(')
1912 { 1953 {
1913 val = read_list (0, readcharfun); 1954 val = read_list (0, readcharfun);
@@ -1915,7 +1956,6 @@ readevalloop (Lisp_Object readcharfun,
1915 else 1956 else
1916 { 1957 {
1917 UNREAD (c); 1958 UNREAD (c);
1918 read_objects = Qnil;
1919 if (!NILP (readfun)) 1959 if (!NILP (readfun))
1920 { 1960 {
1921 val = call1 (readfun, readcharfun); 1961 val = call1 (readfun, readcharfun);
@@ -1935,6 +1975,13 @@ readevalloop (Lisp_Object readcharfun,
1935 else 1975 else
1936 val = read_internal_start (readcharfun, Qnil, Qnil); 1976 val = read_internal_start (readcharfun, Qnil, Qnil);
1937 } 1977 }
1978 /* Empty hashes can be reused; otherwise, reset on next call. */
1979 if (HASH_TABLE_P (read_objects_map)
1980 && XHASH_TABLE (read_objects_map)->count > 0)
1981 read_objects_map = Qnil;
1982 if (HASH_TABLE_P (read_objects_completed)
1983 && XHASH_TABLE (read_objects_completed)->count > 0)
1984 read_objects_completed = Qnil;
1938 1985
1939 if (!NILP (start) && continue_reading_p) 1986 if (!NILP (start) && continue_reading_p)
1940 start = Fpoint_marker (); 1987 start = Fpoint_marker ();
@@ -2106,7 +2153,18 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
2106 2153
2107 readchar_count = 0; 2154 readchar_count = 0;
2108 new_backquote_flag = 0; 2155 new_backquote_flag = 0;
2109 read_objects = Qnil; 2156 /* We can get called from readevalloop which may have set these
2157 already. */
2158 if (! HASH_TABLE_P (read_objects_map)
2159 || XHASH_TABLE (read_objects_map)->count)
2160 read_objects_map
2161 = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
2162 DEFAULT_REHASH_THRESHOLD, Qnil, Qnil);
2163 if (! HASH_TABLE_P (read_objects_completed)
2164 || XHASH_TABLE (read_objects_completed)->count)
2165 read_objects_completed
2166 = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
2167 DEFAULT_REHASH_THRESHOLD, Qnil, Qnil);
2110 if (EQ (Vread_with_symbol_positions, Qt) 2168 if (EQ (Vread_with_symbol_positions, Qt)
2111 || EQ (Vread_with_symbol_positions, stream)) 2169 || EQ (Vread_with_symbol_positions, stream))
2112 Vread_symbol_positions_list = Qnil; 2170 Vread_symbol_positions_list = Qnil;
@@ -2134,6 +2192,13 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
2134 if (EQ (Vread_with_symbol_positions, Qt) 2192 if (EQ (Vread_with_symbol_positions, Qt)
2135 || EQ (Vread_with_symbol_positions, stream)) 2193 || EQ (Vread_with_symbol_positions, stream))
2136 Vread_symbol_positions_list = Fnreverse (Vread_symbol_positions_list); 2194 Vread_symbol_positions_list = Fnreverse (Vread_symbol_positions_list);
2195 /* Empty hashes can be reused; otherwise, reset on next call. */
2196 if (HASH_TABLE_P (read_objects_map)
2197 && XHASH_TABLE (read_objects_map)->count > 0)
2198 read_objects_map = Qnil;
2199 if (HASH_TABLE_P (read_objects_completed)
2200 && XHASH_TABLE (read_objects_completed)->count > 0)
2201 read_objects_completed = Qnil;
2137 return retval; 2202 return retval;
2138} 2203}
2139 2204
@@ -2901,7 +2966,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2901 /* Copy that many characters into saved_doc_string. */ 2966 /* Copy that many characters into saved_doc_string. */
2902 block_input (); 2967 block_input ();
2903 for (i = 0; i < nskip && c >= 0; i++) 2968 for (i = 0; i < nskip && c >= 0; i++)
2904 saved_doc_string[i] = c = getc (instream); 2969 saved_doc_string[i] = c = getc_unlocked (instream);
2905 unblock_input (); 2970 unblock_input ();
2906 2971
2907 saved_doc_string_length = i; 2972 saved_doc_string_length = i;
@@ -2974,7 +3039,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2974 /* Note: We used to use AUTO_CONS to allocate 3039 /* Note: We used to use AUTO_CONS to allocate
2975 placeholder, but that is a bad idea, since it 3040 placeholder, but that is a bad idea, since it
2976 will place a stack-allocated cons cell into 3041 will place a stack-allocated cons cell into
2977 the list in read_objects, which is a 3042 the list in read_objects_map, which is a
2978 staticpro'd global variable, and thus each of 3043 staticpro'd global variable, and thus each of
2979 its elements is marked during each GC. A 3044 its elements is marked during each GC. A
2980 stack-allocated object will become garbled 3045 stack-allocated object will become garbled
@@ -2983,27 +3048,62 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2983 different purposes, which will cause crashes 3048 different purposes, which will cause crashes
2984 in GC. */ 3049 in GC. */
2985 Lisp_Object placeholder = Fcons (Qnil, Qnil); 3050 Lisp_Object placeholder = Fcons (Qnil, Qnil);
2986 Lisp_Object cell = Fcons (make_number (n), placeholder); 3051 struct Lisp_Hash_Table *h
2987 read_objects = Fcons (cell, read_objects); 3052 = XHASH_TABLE (read_objects_map);
3053 EMACS_UINT hash;
3054 Lisp_Object number = make_number (n);
3055
3056 ptrdiff_t i = hash_lookup (h, number, &hash);
3057 if (i >= 0)
3058 /* Not normal, but input could be malformed. */
3059 set_hash_value_slot (h, i, placeholder);
3060 else
3061 hash_put (h, number, placeholder, hash);
2988 3062
2989 /* Read the object itself. */ 3063 /* Read the object itself. */
2990 tem = read0 (readcharfun); 3064 tem = read0 (readcharfun);
2991 3065
3066 /* If it can be recursive, remember it for
3067 future substitutions. */
3068 if (! SYMBOLP (tem)
3069 && ! NUMBERP (tem)
3070 && ! (STRINGP (tem) && !string_intervals (tem)))
3071 {
3072 struct Lisp_Hash_Table *h2
3073 = XHASH_TABLE (read_objects_completed);
3074 i = hash_lookup (h2, tem, &hash);
3075 eassert (i < 0);
3076 hash_put (h2, tem, Qnil, hash);
3077 }
3078
2992 /* Now put it everywhere the placeholder was... */ 3079 /* Now put it everywhere the placeholder was... */
2993 Fsubstitute_object_in_subtree (tem, placeholder); 3080 if (CONSP (tem))
3081 {
3082 Fsetcar (placeholder, XCAR (tem));
3083 Fsetcdr (placeholder, XCDR (tem));
3084 return placeholder;
3085 }
3086 else
3087 {
3088 Fsubstitute_object_in_subtree (tem, placeholder);
2994 3089
2995 /* ...and #n# will use the real value from now on. */ 3090 /* ...and #n# will use the real value from now on. */
2996 Fsetcdr (cell, tem); 3091 i = hash_lookup (h, number, &hash);
3092 eassert (i >= 0);
3093 set_hash_value_slot (h, i, tem);
2997 3094
2998 return tem; 3095 return tem;
3096 }
2999 } 3097 }
3000 3098
3001 /* #n# returns a previously read object. */ 3099 /* #n# returns a previously read object. */
3002 if (c == '#') 3100 if (c == '#')
3003 { 3101 {
3004 tem = Fassq (make_number (n), read_objects); 3102 struct Lisp_Hash_Table *h
3005 if (CONSP (tem)) 3103 = XHASH_TABLE (read_objects_map);
3006 return XCDR (tem); 3104 ptrdiff_t i = hash_lookup (h, make_number (n), NULL);
3105 if (i >= 0)
3106 return HASH_VALUE (h, i);
3007 } 3107 }
3008 } 3108 }
3009 } 3109 }
@@ -3342,25 +3442,51 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3342 if (! NILP (result)) 3442 if (! NILP (result))
3343 return unbind_to (count, result); 3443 return unbind_to (count, result);
3344 } 3444 }
3445 {
3446 Lisp_Object result;
3447 ptrdiff_t nbytes = p - read_buffer;
3448 ptrdiff_t nchars
3449 = (multibyte
3450 ? multibyte_chars_in_text ((unsigned char *) read_buffer,
3451 nbytes)
3452 : nbytes);
3453
3454 if (uninterned_symbol)
3455 {
3456 Lisp_Object name
3457 = ((! NILP (Vpurify_flag)
3458 ? make_pure_string : make_specified_string)
3459 (read_buffer, nchars, nbytes, multibyte));
3460 result = Fmake_symbol (name);
3461 }
3462 else
3463 {
3464 /* Don't create the string object for the name unless
3465 we're going to retain it in a new symbol.
3345 3466
3346 ptrdiff_t nbytes = p - read_buffer; 3467 Like intern_1 but supports multibyte names. */
3347 ptrdiff_t nchars 3468 Lisp_Object obarray = check_obarray (Vobarray);
3348 = (multibyte 3469 Lisp_Object tem = oblookup (obarray, read_buffer,
3349 ? multibyte_chars_in_text ((unsigned char *) read_buffer, 3470 nchars, nbytes);
3350 nbytes) 3471
3351 : nbytes); 3472 if (SYMBOLP (tem))
3352 Lisp_Object name = ((uninterned_symbol && ! NILP (Vpurify_flag) 3473 result = tem;
3353 ? make_pure_string : make_specified_string) 3474 else
3354 (read_buffer, nchars, nbytes, multibyte)); 3475 {
3355 Lisp_Object result = (uninterned_symbol ? Fmake_symbol (name) 3476 Lisp_Object name
3356 : Fintern (name, Qnil)); 3477 = make_specified_string (read_buffer, nchars, nbytes,
3357 3478 multibyte);
3358 if (EQ (Vread_with_symbol_positions, Qt) 3479 result = intern_driver (name, obarray, tem);
3359 || EQ (Vread_with_symbol_positions, readcharfun)) 3480 }
3360 Vread_symbol_positions_list 3481 }
3361 = Fcons (Fcons (result, make_number (start_position)), 3482
3362 Vread_symbol_positions_list); 3483 if (EQ (Vread_with_symbol_positions, Qt)
3363 return unbind_to (count, result); 3484 || EQ (Vread_with_symbol_positions, readcharfun))
3485 Vread_symbol_positions_list
3486 = Fcons (Fcons (result, make_number (start_position)),
3487 Vread_symbol_positions_list);
3488 return unbind_to (count, result);
3489 }
3364 } 3490 }
3365 } 3491 }
3366} 3492}
@@ -3414,6 +3540,13 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj
3414 if (EQ (placeholder, subtree)) 3540 if (EQ (placeholder, subtree))
3415 return object; 3541 return object;
3416 3542
3543 /* For common object types that can't contain other objects, don't
3544 bother looking them up; we're done. */
3545 if (SYMBOLP (subtree)
3546 || (STRINGP (subtree) && !string_intervals (subtree))
3547 || NUMBERP (subtree))
3548 return subtree;
3549
3417 /* If we've been to this node before, don't explore it again. */ 3550 /* If we've been to this node before, don't explore it again. */
3418 if (!EQ (Qnil, Fmemq (subtree, seen_list))) 3551 if (!EQ (Qnil, Fmemq (subtree, seen_list)))
3419 return subtree; 3552 return subtree;
@@ -3421,8 +3554,8 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj
3421 /* If this node can be the entry point to a cycle, remember that 3554 /* If this node can be the entry point to a cycle, remember that
3422 we've seen it. It can only be such an entry point if it was made 3555 we've seen it. It can only be such an entry point if it was made
3423 by #n=, which means that we can find it as a value in 3556 by #n=, which means that we can find it as a value in
3424 read_objects. */ 3557 read_objects_completed. */
3425 if (!EQ (Qnil, Frassq (subtree, read_objects))) 3558 if (hash_lookup (XHASH_TABLE (read_objects_completed), subtree, NULL) >= 0)
3426 seen_list = Fcons (subtree, seen_list); 3559 seen_list = Fcons (subtree, seen_list);
3427 3560
3428 /* Recurse according to subtree's type. 3561 /* Recurse according to subtree's type.
@@ -4898,8 +5031,10 @@ that are loaded before your customizations are read! */);
4898 DEFSYM (Qdir_ok, "dir-ok"); 5031 DEFSYM (Qdir_ok, "dir-ok");
4899 DEFSYM (Qdo_after_load_evaluation, "do-after-load-evaluation"); 5032 DEFSYM (Qdo_after_load_evaluation, "do-after-load-evaluation");
4900 5033
4901 staticpro (&read_objects); 5034 staticpro (&read_objects_map);
4902 read_objects = Qnil; 5035 read_objects_map = Qnil;
5036 staticpro (&read_objects_completed);
5037 read_objects_completed = Qnil;
4903 staticpro (&seen_list); 5038 staticpro (&seen_list);
4904 seen_list = Qnil; 5039 seen_list = Qnil;
4905 5040