diff options
| author | Paul Eggert | 2017-03-29 22:34:02 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-03-29 22:43:51 -0700 |
| commit | 080a425db51e0b26b03f0f4bd06c814fc2b38578 (patch) | |
| tree | efd3c6c3b46251dd3fe97332f55e6e03daf8c317 | |
| parent | b7ec73f6905df99978f7183ac8e83a3be56edc6c (diff) | |
| download | emacs-080a425db51e0b26b03f0f4bd06c814fc2b38578.tar.gz emacs-080a425db51e0b26b03f0f4bd06c814fc2b38578.zip | |
Fix assoc_no_quit so that it does not quit
The problem was that it called Fequal, which can quit.
* src/fns.c (enum equal_kind):
New enum, to be used in place of a boolean.
(equal_no_quit): New function.
(Fmemql, Feql): Use it to compare floats, as a minor tuneup.
(assoc_no_quit): Use it to avoid quitting, the main point here.
(internal_equal): Generalize bool to enum equal_kind arg, so that
there are now 3 possibilities instead of 2. Do not signal an
error if EQUAL_NO_QUIT. Put the arg before the depth, since depth
should be irrelevant if the arg is EQUAL_NO_QUIT. All callers
changed.
| -rw-r--r-- | src/fns.c | 122 |
1 files changed, 80 insertions, 42 deletions
| @@ -38,7 +38,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 38 | 38 | ||
| 39 | static void sort_vector_copy (Lisp_Object, ptrdiff_t, | 39 | static void sort_vector_copy (Lisp_Object, ptrdiff_t, |
| 40 | Lisp_Object *restrict, Lisp_Object *restrict); | 40 | Lisp_Object *restrict, Lisp_Object *restrict); |
| 41 | static bool internal_equal (Lisp_Object, Lisp_Object, int, bool, Lisp_Object); | 41 | static bool equal_no_quit (Lisp_Object, Lisp_Object); |
| 42 | enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES }; | ||
| 43 | static bool internal_equal (Lisp_Object, Lisp_Object, | ||
| 44 | enum equal_kind, int, Lisp_Object); | ||
| 42 | 45 | ||
| 43 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, | 46 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, |
| 44 | doc: /* Return the argument unchanged. */ | 47 | doc: /* Return the argument unchanged. */ |
| @@ -1377,7 +1380,7 @@ The value is actually the tail of LIST whose car is ELT. */) | |||
| 1377 | FOR_EACH_TAIL (tail) | 1380 | FOR_EACH_TAIL (tail) |
| 1378 | { | 1381 | { |
| 1379 | Lisp_Object tem = XCAR (tail); | 1382 | Lisp_Object tem = XCAR (tail); |
| 1380 | if (FLOATP (tem) && internal_equal (elt, tem, 0, 0, Qnil)) | 1383 | if (FLOATP (tem) && equal_no_quit (elt, tem)) |
| 1381 | return tail; | 1384 | return tail; |
| 1382 | } | 1385 | } |
| 1383 | CHECK_LIST_END (tail, list); | 1386 | CHECK_LIST_END (tail, list); |
| @@ -1428,7 +1431,8 @@ The value is actually the first element of LIST whose car equals KEY. */) | |||
| 1428 | } | 1431 | } |
| 1429 | 1432 | ||
| 1430 | /* Like Fassoc but never report an error and do not allow quits. | 1433 | /* Like Fassoc but never report an error and do not allow quits. |
| 1431 | Use only on objects known to be non-circular lists. */ | 1434 | Use only on keys and lists known to be non-circular, and on keys |
| 1435 | that are not too deep and are not window configurations. */ | ||
| 1432 | 1436 | ||
| 1433 | Lisp_Object | 1437 | Lisp_Object |
| 1434 | assoc_no_quit (Lisp_Object key, Lisp_Object list) | 1438 | assoc_no_quit (Lisp_Object key, Lisp_Object list) |
| @@ -1437,7 +1441,7 @@ assoc_no_quit (Lisp_Object key, Lisp_Object list) | |||
| 1437 | { | 1441 | { |
| 1438 | Lisp_Object car = XCAR (list); | 1442 | Lisp_Object car = XCAR (list); |
| 1439 | if (CONSP (car) | 1443 | if (CONSP (car) |
| 1440 | && (EQ (XCAR (car), key) || !NILP (Fequal (XCAR (car), key)))) | 1444 | && (EQ (XCAR (car), key) || equal_no_quit (XCAR (car), key))) |
| 1441 | return car; | 1445 | return car; |
| 1442 | } | 1446 | } |
| 1443 | return Qnil; | 1447 | return Qnil; |
| @@ -2085,7 +2089,7 @@ Floating-point numbers of equal value are `eql', but they may not be `eq'. */) | |||
| 2085 | (Lisp_Object obj1, Lisp_Object obj2) | 2089 | (Lisp_Object obj1, Lisp_Object obj2) |
| 2086 | { | 2090 | { |
| 2087 | if (FLOATP (obj1)) | 2091 | if (FLOATP (obj1)) |
| 2088 | return internal_equal (obj1, obj2, 0, 0, Qnil) ? Qt : Qnil; | 2092 | return equal_no_quit (obj1, obj2) ? Qt : Qnil; |
| 2089 | else | 2093 | else |
| 2090 | return EQ (obj1, obj2) ? Qt : Qnil; | 2094 | return EQ (obj1, obj2) ? Qt : Qnil; |
| 2091 | } | 2095 | } |
| @@ -2098,31 +2102,50 @@ Vectors and strings are compared element by element. | |||
| 2098 | Numbers are compared by value, but integers cannot equal floats. | 2102 | Numbers are compared by value, but integers cannot equal floats. |
| 2099 | (Use `=' if you want integers and floats to be able to be equal.) | 2103 | (Use `=' if you want integers and floats to be able to be equal.) |
| 2100 | Symbols must match exactly. */) | 2104 | Symbols must match exactly. */) |
| 2101 | (register Lisp_Object o1, Lisp_Object o2) | 2105 | (Lisp_Object o1, Lisp_Object o2) |
| 2102 | { | 2106 | { |
| 2103 | return internal_equal (o1, o2, 0, 0, Qnil) ? Qt : Qnil; | 2107 | return internal_equal (o1, o2, EQUAL_PLAIN, 0, Qnil) ? Qt : Qnil; |
| 2104 | } | 2108 | } |
| 2105 | 2109 | ||
| 2106 | DEFUN ("equal-including-properties", Fequal_including_properties, Sequal_including_properties, 2, 2, 0, | 2110 | DEFUN ("equal-including-properties", Fequal_including_properties, Sequal_including_properties, 2, 2, 0, |
| 2107 | doc: /* Return t if two Lisp objects have similar structure and contents. | 2111 | doc: /* Return t if two Lisp objects have similar structure and contents. |
| 2108 | This is like `equal' except that it compares the text properties | 2112 | This is like `equal' except that it compares the text properties |
| 2109 | of strings. (`equal' ignores text properties.) */) | 2113 | of strings. (`equal' ignores text properties.) */) |
| 2110 | (register Lisp_Object o1, Lisp_Object o2) | 2114 | (Lisp_Object o1, Lisp_Object o2) |
| 2115 | { | ||
| 2116 | return (internal_equal (o1, o2, EQUAL_INCLUDING_PROPERTIES, 0, Qnil) | ||
| 2117 | ? Qt : Qnil); | ||
| 2118 | } | ||
| 2119 | |||
| 2120 | /* Return true if O1 and O2 are equal. Do not quit or check for cycles. | ||
| 2121 | Use this only on arguments that are cycle-free and not too large and | ||
| 2122 | are not window configurations. */ | ||
| 2123 | |||
| 2124 | static bool | ||
| 2125 | equal_no_quit (Lisp_Object o1, Lisp_Object o2) | ||
| 2111 | { | 2126 | { |
| 2112 | return internal_equal (o1, o2, 0, 1, Qnil) ? Qt : Qnil; | 2127 | return internal_equal (o1, o2, EQUAL_NO_QUIT, 0, Qnil); |
| 2113 | } | 2128 | } |
| 2114 | 2129 | ||
| 2115 | /* DEPTH is current depth of recursion. Signal an error if it | 2130 | /* Return true if O1 and O2 are equal. EQUAL_KIND specifies what kind |
| 2116 | gets too deep. | 2131 | of equality test to use: if it is EQUAL_NO_QUIT, do not check for |
| 2117 | PROPS means compare string text properties too. */ | 2132 | cycles or large arguments or quits; if EQUAL_PLAIN, do ordinary |
| 2133 | Lisp equality; and if EQUAL_INCLUDING_PROPERTIES, do | ||
| 2134 | equal-including-properties. | ||
| 2135 | |||
| 2136 | If DEPTH is the current depth of recursion; signal an error if it | ||
| 2137 | gets too deep. HT is a hash table used to detect cycles; if nil, | ||
| 2138 | it has not been allocated yet. But ignore the last two arguments | ||
| 2139 | if EQUAL_KIND == EQUAL_NO_QUIT. */ | ||
| 2118 | 2140 | ||
| 2119 | static bool | 2141 | static bool |
| 2120 | internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | 2142 | internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind, |
| 2121 | Lisp_Object ht) | 2143 | int depth, Lisp_Object ht) |
| 2122 | { | 2144 | { |
| 2123 | tail_recurse: | 2145 | tail_recurse: |
| 2124 | if (depth > 10) | 2146 | if (depth > 10) |
| 2125 | { | 2147 | { |
| 2148 | eassert (equal_kind != EQUAL_NO_QUIT); | ||
| 2126 | if (depth > 200) | 2149 | if (depth > 200) |
| 2127 | error ("Stack overflow in equal"); | 2150 | error ("Stack overflow in equal"); |
| 2128 | if (NILP (ht)) | 2151 | if (NILP (ht)) |
| @@ -2138,7 +2161,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2138 | { /* `o1' was seen already. */ | 2161 | { /* `o1' was seen already. */ |
| 2139 | Lisp_Object o2s = HASH_VALUE (h, i); | 2162 | Lisp_Object o2s = HASH_VALUE (h, i); |
| 2140 | if (!NILP (Fmemq (o2, o2s))) | 2163 | if (!NILP (Fmemq (o2, o2s))) |
| 2141 | return 1; | 2164 | return true; |
| 2142 | else | 2165 | else |
| 2143 | set_hash_value_slot (h, i, Fcons (o2, o2s)); | 2166 | set_hash_value_slot (h, i, Fcons (o2, o2s)); |
| 2144 | } | 2167 | } |
| @@ -2150,9 +2173,9 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2150 | } | 2173 | } |
| 2151 | 2174 | ||
| 2152 | if (EQ (o1, o2)) | 2175 | if (EQ (o1, o2)) |
| 2153 | return 1; | 2176 | return true; |
| 2154 | if (XTYPE (o1) != XTYPE (o2)) | 2177 | if (XTYPE (o1) != XTYPE (o2)) |
| 2155 | return 0; | 2178 | return false; |
| 2156 | 2179 | ||
| 2157 | switch (XTYPE (o1)) | 2180 | switch (XTYPE (o1)) |
| 2158 | { | 2181 | { |
| @@ -2166,31 +2189,42 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2166 | } | 2189 | } |
| 2167 | 2190 | ||
| 2168 | case Lisp_Cons: | 2191 | case Lisp_Cons: |
| 2169 | { | 2192 | if (equal_kind == EQUAL_NO_QUIT) |
| 2193 | for (; CONSP (o1); o1 = XCDR (o1)) | ||
| 2194 | { | ||
| 2195 | if (! CONSP (o2)) | ||
| 2196 | return false; | ||
| 2197 | if (! equal_no_quit (XCAR (o1), XCAR (o2))) | ||
| 2198 | return false; | ||
| 2199 | o2 = XCDR (o2); | ||
| 2200 | if (EQ (XCDR (o1), o2)) | ||
| 2201 | return true; | ||
| 2202 | } | ||
| 2203 | else | ||
| 2170 | FOR_EACH_TAIL (o1) | 2204 | FOR_EACH_TAIL (o1) |
| 2171 | { | 2205 | { |
| 2172 | if (! CONSP (o2)) | 2206 | if (! CONSP (o2)) |
| 2173 | return false; | 2207 | return false; |
| 2174 | if (! internal_equal (XCAR (o1), XCAR (o2), depth + 1, props, ht)) | 2208 | if (! internal_equal (XCAR (o1), XCAR (o2), |
| 2209 | equal_kind, depth + 1, ht)) | ||
| 2175 | return false; | 2210 | return false; |
| 2176 | o2 = XCDR (o2); | 2211 | o2 = XCDR (o2); |
| 2177 | if (EQ (XCDR (o1), o2)) | 2212 | if (EQ (XCDR (o1), o2)) |
| 2178 | return true; | 2213 | return true; |
| 2179 | } | 2214 | } |
| 2180 | depth++; | 2215 | depth++; |
| 2181 | goto tail_recurse; | 2216 | goto tail_recurse; |
| 2182 | } | ||
| 2183 | 2217 | ||
| 2184 | case Lisp_Misc: | 2218 | case Lisp_Misc: |
| 2185 | if (XMISCTYPE (o1) != XMISCTYPE (o2)) | 2219 | if (XMISCTYPE (o1) != XMISCTYPE (o2)) |
| 2186 | return 0; | 2220 | return false; |
| 2187 | if (OVERLAYP (o1)) | 2221 | if (OVERLAYP (o1)) |
| 2188 | { | 2222 | { |
| 2189 | if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o2), | 2223 | if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o2), |
| 2190 | depth + 1, props, ht) | 2224 | equal_kind, depth + 1, ht) |
| 2191 | || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o2), | 2225 | || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o2), |
| 2192 | depth + 1, props, ht)) | 2226 | equal_kind, depth + 1, ht)) |
| 2193 | return 0; | 2227 | return false; |
| 2194 | o1 = XOVERLAY (o1)->plist; | 2228 | o1 = XOVERLAY (o1)->plist; |
| 2195 | o2 = XOVERLAY (o2)->plist; | 2229 | o2 = XOVERLAY (o2)->plist; |
| 2196 | depth++; | 2230 | depth++; |
| @@ -2212,20 +2246,23 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2212 | actually checks that the objects have the same type as well as the | 2246 | actually checks that the objects have the same type as well as the |
| 2213 | same size. */ | 2247 | same size. */ |
| 2214 | if (ASIZE (o2) != size) | 2248 | if (ASIZE (o2) != size) |
| 2215 | return 0; | 2249 | return false; |
| 2216 | /* Boolvectors are compared much like strings. */ | 2250 | /* Boolvectors are compared much like strings. */ |
| 2217 | if (BOOL_VECTOR_P (o1)) | 2251 | if (BOOL_VECTOR_P (o1)) |
| 2218 | { | 2252 | { |
| 2219 | EMACS_INT size = bool_vector_size (o1); | 2253 | EMACS_INT size = bool_vector_size (o1); |
| 2220 | if (size != bool_vector_size (o2)) | 2254 | if (size != bool_vector_size (o2)) |
| 2221 | return 0; | 2255 | return false; |
| 2222 | if (memcmp (bool_vector_data (o1), bool_vector_data (o2), | 2256 | if (memcmp (bool_vector_data (o1), bool_vector_data (o2), |
| 2223 | bool_vector_bytes (size))) | 2257 | bool_vector_bytes (size))) |
| 2224 | return 0; | 2258 | return false; |
| 2225 | return 1; | 2259 | return true; |
| 2226 | } | 2260 | } |
| 2227 | if (WINDOW_CONFIGURATIONP (o1)) | 2261 | if (WINDOW_CONFIGURATIONP (o1)) |
| 2228 | return compare_window_configurations (o1, o2, 0); | 2262 | { |
| 2263 | eassert (equal_kind != EQUAL_NO_QUIT); | ||
| 2264 | return compare_window_configurations (o1, o2, false); | ||
| 2265 | } | ||
| 2229 | 2266 | ||
| 2230 | /* Aside from them, only true vectors, char-tables, compiled | 2267 | /* Aside from them, only true vectors, char-tables, compiled |
| 2231 | functions, and fonts (font-spec, font-entity, font-object) | 2268 | functions, and fonts (font-spec, font-entity, font-object) |
| @@ -2234,7 +2271,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2234 | { | 2271 | { |
| 2235 | if (((size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS) | 2272 | if (((size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS) |
| 2236 | < PVEC_COMPILED) | 2273 | < PVEC_COMPILED) |
| 2237 | return 0; | 2274 | return false; |
| 2238 | size &= PSEUDOVECTOR_SIZE_MASK; | 2275 | size &= PSEUDOVECTOR_SIZE_MASK; |
| 2239 | } | 2276 | } |
| 2240 | for (i = 0; i < size; i++) | 2277 | for (i = 0; i < size; i++) |
| @@ -2242,29 +2279,30 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2242 | Lisp_Object v1, v2; | 2279 | Lisp_Object v1, v2; |
| 2243 | v1 = AREF (o1, i); | 2280 | v1 = AREF (o1, i); |
| 2244 | v2 = AREF (o2, i); | 2281 | v2 = AREF (o2, i); |
| 2245 | if (!internal_equal (v1, v2, depth + 1, props, ht)) | 2282 | if (!internal_equal (v1, v2, equal_kind, depth + 1, ht)) |
| 2246 | return 0; | 2283 | return false; |
| 2247 | } | 2284 | } |
| 2248 | return 1; | 2285 | return true; |
| 2249 | } | 2286 | } |
| 2250 | break; | 2287 | break; |
| 2251 | 2288 | ||
| 2252 | case Lisp_String: | 2289 | case Lisp_String: |
| 2253 | if (SCHARS (o1) != SCHARS (o2)) | 2290 | if (SCHARS (o1) != SCHARS (o2)) |
| 2254 | return 0; | 2291 | return false; |
| 2255 | if (SBYTES (o1) != SBYTES (o2)) | 2292 | if (SBYTES (o1) != SBYTES (o2)) |
| 2256 | return 0; | 2293 | return false; |
| 2257 | if (memcmp (SDATA (o1), SDATA (o2), SBYTES (o1))) | 2294 | if (memcmp (SDATA (o1), SDATA (o2), SBYTES (o1))) |
| 2258 | return 0; | 2295 | return false; |
| 2259 | if (props && !compare_string_intervals (o1, o2)) | 2296 | if (equal_kind == EQUAL_INCLUDING_PROPERTIES |
| 2260 | return 0; | 2297 | && !compare_string_intervals (o1, o2)) |
| 2261 | return 1; | 2298 | return false; |
| 2299 | return true; | ||
| 2262 | 2300 | ||
| 2263 | default: | 2301 | default: |
| 2264 | break; | 2302 | break; |
| 2265 | } | 2303 | } |
| 2266 | 2304 | ||
| 2267 | return 0; | 2305 | return false; |
| 2268 | } | 2306 | } |
| 2269 | 2307 | ||
| 2270 | 2308 | ||