diff options
| author | Ken Raeburn | 2017-06-21 22:45:14 -0400 |
|---|---|---|
| committer | Ken Raeburn | 2017-06-21 22:46:10 -0400 |
| commit | 85f6aa33f55da97b13b5e81616f16a517d24f3d5 (patch) | |
| tree | 76533b2a92306346ac591e93f52555a0708ac5dc /src | |
| parent | 87a44b934ccecd2d9bdbf0afad576333741075b6 (diff) | |
| parent | 59f3c86659c061e2673eb0da0bc78528d30f8f76 (diff) | |
| download | emacs-85f6aa33f55da97b13b5e81616f16a517d24f3d5.tar.gz emacs-85f6aa33f55da97b13b5e81616f16a517d24f3d5.zip | |
Merge several Lisp reader speedups.
Diffstat (limited to 'src')
| -rw-r--r-- | src/charset.c | 14 | ||||
| -rw-r--r-- | src/lread.c | 221 |
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 | |
| 79 | static 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. */ | ||
| 91 | static 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. */ | ||
| 108 | static 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. */ |
| 82 | static FILE *instream; | 111 | static 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 | ||