diff options
| author | Paul Eggert | 2019-07-22 21:27:33 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-07-22 21:28:18 -0700 |
| commit | f378ed1a0b1ca2ceed5afabcf5f303ae339039ba (patch) | |
| tree | 767e994477690e2681cb7fe027af7d708efd6cc6 | |
| parent | 97477edaf2044e51696f46b166b43801893156a3 (diff) | |
| download | emacs-f378ed1a0b1ca2ceed5afabcf5f303ae339039ba.tar.gz emacs-f378ed1a0b1ca2ceed5afabcf5f303ae339039ba.zip | |
Avoid overexposing fixnums for hash codes
Following a suggestion by Stefan Monnier in:
https://lists.gnu.org/r/emacs-devel/2019-07/msg00530.html
* doc/lispref/hash.texi (Creating Hash, Defining Hash):
* src/fns.c (Fsxhash_eq, Fsxhash_eql, Fsxhash_equal, Fmake_hash_table):
Don’t insist that hash codes be fixnums, reverting
the recent doc changes to the contrary.
* src/bytecode.c (exec_byte_code): Special-case only the eq case,
as the others aren’t worth tuning now that we treat bignum hashes
like fixnums.
* src/fns.c (hashfn_user_defined): If the hash code is a bignum,
reduce its hash down to a fixnum.
| -rw-r--r-- | doc/lispref/hash.texi | 16 | ||||
| -rw-r--r-- | src/bytecode.c | 14 | ||||
| -rw-r--r-- | src/fns.c | 12 |
3 files changed, 19 insertions, 23 deletions
diff --git a/doc/lispref/hash.texi b/doc/lispref/hash.texi index 051531491c0..50d4c5742cb 100644 --- a/doc/lispref/hash.texi +++ b/doc/lispref/hash.texi | |||
| @@ -132,7 +132,7 @@ When you add an association to a hash table and the table is full, | |||
| 132 | it grows automatically. This value specifies how to make the hash table | 132 | it grows automatically. This value specifies how to make the hash table |
| 133 | larger, at that time. | 133 | larger, at that time. |
| 134 | 134 | ||
| 135 | If @var{rehash-size} is a fixnum, it should be positive and the hash | 135 | If @var{rehash-size} is an integer, it should be positive, and the hash |
| 136 | table grows by adding approximately that much to the nominal size. If | 136 | table grows by adding approximately that much to the nominal size. If |
| 137 | @var{rehash-size} is floating point, it had better be greater | 137 | @var{rehash-size} is floating point, it had better be greater |
| 138 | than 1, and the hash table grows by multiplying the old size by | 138 | than 1, and the hash table grows by multiplying the old size by |
| @@ -239,8 +239,8 @@ to understand how hash tables work, and what a @dfn{hash code} means. | |||
| 239 | 239 | ||
| 240 | You can think of a hash table conceptually as a large array of many | 240 | You can think of a hash table conceptually as a large array of many |
| 241 | slots, each capable of holding one association. To look up a key, | 241 | slots, each capable of holding one association. To look up a key, |
| 242 | @code{gethash} first computes a fixnum, the hash code, from the key. | 242 | @code{gethash} first computes an integer, the hash code, from the key. |
| 243 | It reduces this fixnum modulo the length of the array, to produce an | 243 | It can reduce this integer modulo the length of the array, to produce an |
| 244 | index in the array. Then it looks in that slot, and if necessary in | 244 | index in the array. Then it looks in that slot, and if necessary in |
| 245 | other nearby slots, to see if it has found the key being sought. | 245 | other nearby slots, to see if it has found the key being sought. |
| 246 | 246 | ||
| @@ -265,7 +265,7 @@ The function @var{test-fn} should accept two arguments, two keys, and | |||
| 265 | return non-@code{nil} if they are considered the same. | 265 | return non-@code{nil} if they are considered the same. |
| 266 | 266 | ||
| 267 | The function @var{hash-fn} should accept one argument, a key, and return | 267 | The function @var{hash-fn} should accept one argument, a key, and return |
| 268 | a fixnum that is the hash code of that key. For good results, the | 268 | an integer that is the hash code of that key. For good results, the |
| 269 | function should use the whole range of fixnums for hash codes, | 269 | function should use the whole range of fixnums for hash codes, |
| 270 | including negative fixnums. | 270 | including negative fixnums. |
| 271 | 271 | ||
| @@ -276,12 +276,12 @@ under the property @code{hash-table-test}; the property value's form is | |||
| 276 | 276 | ||
| 277 | @defun sxhash-equal obj | 277 | @defun sxhash-equal obj |
| 278 | This function returns a hash code for Lisp object @var{obj}. | 278 | This function returns a hash code for Lisp object @var{obj}. |
| 279 | This is a fixnum that reflects the contents of @var{obj} | 279 | This is an integer that reflects the contents of @var{obj} |
| 280 | and the other Lisp objects it points to. | 280 | and the other Lisp objects it points to. |
| 281 | 281 | ||
| 282 | If two objects @var{obj1} and @var{obj2} are @code{equal}, then | 282 | If two objects @var{obj1} and @var{obj2} are @code{equal}, then |
| 283 | @code{(sxhash-equal @var{obj1})} and @code{(sxhash-equal @var{obj2})} | 283 | @code{(sxhash-equal @var{obj1})} and @code{(sxhash-equal @var{obj2})} |
| 284 | are the same fixnum. | 284 | are the same integer. |
| 285 | 285 | ||
| 286 | If the two objects are not @code{equal}, the values returned by | 286 | If the two objects are not @code{equal}, the values returned by |
| 287 | @code{sxhash-equal} are usually different, but not always; once in a | 287 | @code{sxhash-equal} are usually different, but not always; once in a |
| @@ -299,7 +299,7 @@ result reflects identity of @var{obj}, but not its contents. | |||
| 299 | 299 | ||
| 300 | If two objects @var{obj1} and @var{obj2} are @code{eq}, then | 300 | If two objects @var{obj1} and @var{obj2} are @code{eq}, then |
| 301 | @code{(sxhash-eq @var{obj1})} and @code{(sxhash-eq @var{obj2})} are | 301 | @code{(sxhash-eq @var{obj1})} and @code{(sxhash-eq @var{obj2})} are |
| 302 | the same fixnum. | 302 | the same integer. |
| 303 | @end defun | 303 | @end defun |
| 304 | 304 | ||
| 305 | @defun sxhash-eql obj | 305 | @defun sxhash-eql obj |
| @@ -310,7 +310,7 @@ in which case a hash code is generated for the value. | |||
| 310 | 310 | ||
| 311 | If two objects @var{obj1} and @var{obj2} are @code{eql}, then | 311 | If two objects @var{obj1} and @var{obj2} are @code{eql}, then |
| 312 | @code{(sxhash-eql @var{obj1})} and @code{(sxhash-eql @var{obj2})} are | 312 | @code{(sxhash-eql @var{obj1})} and @code{(sxhash-eql @var{obj2})} are |
| 313 | the same fixnum. | 313 | the same integer. |
| 314 | @end defun | 314 | @end defun |
| 315 | 315 | ||
| 316 | This example creates a hash table whose keys are strings that are | 316 | This example creates a hash table whose keys are strings that are |
diff --git a/src/bytecode.c b/src/bytecode.c index d668a9a6a15..9aad1eb642b 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -1406,18 +1406,12 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1406 | 1406 | ||
| 1407 | /* h->count is a faster approximation for HASH_TABLE_SIZE (h) | 1407 | /* h->count is a faster approximation for HASH_TABLE_SIZE (h) |
| 1408 | here. */ | 1408 | here. */ |
| 1409 | if (h->count <= 5) | 1409 | if (h->count <= 5 && !h->test.cmpfn) |
| 1410 | { /* Do a linear search if there are not many cases | 1410 | { /* Do a linear search if there are not many cases |
| 1411 | FIXME: 5 is arbitrarily chosen. */ | 1411 | FIXME: 5 is arbitrarily chosen. */ |
| 1412 | Lisp_Object hash_code | 1412 | for (i = h->count; 0 <= --i; ) |
| 1413 | = h->test.cmpfn ? h->test.hashfn (v1, h) : Qnil; | 1413 | if (EQ (v1, HASH_KEY (h, i))) |
| 1414 | 1414 | break; | |
| 1415 | for (i = h->count; 0 <= --i; ) | ||
| 1416 | if (EQ (v1, HASH_KEY (h, i)) | ||
| 1417 | || (h->test.cmpfn | ||
| 1418 | && EQ (hash_code, HASH_HASH (h, i)) | ||
| 1419 | && !NILP (h->test.cmpfn (v1, HASH_KEY (h, i), h)))) | ||
| 1420 | break; | ||
| 1421 | } | 1415 | } |
| 1422 | else | 1416 | else |
| 1423 | i = hash_lookup (h, v1, NULL); | 1417 | i = hash_lookup (h, v1, NULL); |
| @@ -47,6 +47,7 @@ static void sort_vector_copy (Lisp_Object, ptrdiff_t, | |||
| 47 | enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES }; | 47 | enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES }; |
| 48 | static bool internal_equal (Lisp_Object, Lisp_Object, | 48 | static bool internal_equal (Lisp_Object, Lisp_Object, |
| 49 | enum equal_kind, int, Lisp_Object); | 49 | enum equal_kind, int, Lisp_Object); |
| 50 | static EMACS_UINT sxhash_bignum (struct Lisp_Bignum *); | ||
| 50 | 51 | ||
| 51 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, | 52 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, |
| 52 | doc: /* Return the argument unchanged. */ | 53 | doc: /* Return the argument unchanged. */ |
| @@ -4021,7 +4022,8 @@ Lisp_Object | |||
| 4021 | hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) | 4022 | hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) |
| 4022 | { | 4023 | { |
| 4023 | Lisp_Object args[] = { h->test.user_hash_function, key }; | 4024 | Lisp_Object args[] = { h->test.user_hash_function, key }; |
| 4024 | return hash_table_user_defined_call (ARRAYELTS (args), args, h); | 4025 | Lisp_Object hash = hash_table_user_defined_call (ARRAYELTS (args), args, h); |
| 4026 | return BIGNUMP (hash) ? make_fixnum (sxhash_bignum (XBIGNUM (hash))) : hash; | ||
| 4025 | } | 4027 | } |
| 4026 | 4028 | ||
| 4027 | struct hash_table_test const | 4029 | struct hash_table_test const |
| @@ -4707,7 +4709,7 @@ sxhash (Lisp_Object obj, int depth) | |||
| 4707 | ***********************************************************************/ | 4709 | ***********************************************************************/ |
| 4708 | 4710 | ||
| 4709 | DEFUN ("sxhash-eq", Fsxhash_eq, Ssxhash_eq, 1, 1, 0, | 4711 | DEFUN ("sxhash-eq", Fsxhash_eq, Ssxhash_eq, 1, 1, 0, |
| 4710 | doc: /* Return a fixnum hash code for OBJ suitable for `eq'. | 4712 | doc: /* Return an integer hash code for OBJ suitable for `eq'. |
| 4711 | If (eq A B), then (= (sxhash-eq A) (sxhash-eq B)). | 4713 | If (eq A B), then (= (sxhash-eq A) (sxhash-eq B)). |
| 4712 | 4714 | ||
| 4713 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) | 4715 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) |
| @@ -4717,7 +4719,7 @@ Hash codes are not guaranteed to be preserved across Emacs sessions. */) | |||
| 4717 | } | 4719 | } |
| 4718 | 4720 | ||
| 4719 | DEFUN ("sxhash-eql", Fsxhash_eql, Ssxhash_eql, 1, 1, 0, | 4721 | DEFUN ("sxhash-eql", Fsxhash_eql, Ssxhash_eql, 1, 1, 0, |
| 4720 | doc: /* Return a fixnum hash code for OBJ suitable for `eql'. | 4722 | doc: /* Return an integer hash code for OBJ suitable for `eql'. |
| 4721 | If (eql A B), then (= (sxhash-eql A) (sxhash-eql B)). | 4723 | If (eql A B), then (= (sxhash-eql A) (sxhash-eql B)). |
| 4722 | 4724 | ||
| 4723 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) | 4725 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) |
| @@ -4727,7 +4729,7 @@ Hash codes are not guaranteed to be preserved across Emacs sessions. */) | |||
| 4727 | } | 4729 | } |
| 4728 | 4730 | ||
| 4729 | DEFUN ("sxhash-equal", Fsxhash_equal, Ssxhash_equal, 1, 1, 0, | 4731 | DEFUN ("sxhash-equal", Fsxhash_equal, Ssxhash_equal, 1, 1, 0, |
| 4730 | doc: /* Return a fixnum hash code for OBJ suitable for `equal'. | 4732 | doc: /* Return an integer hash code for OBJ suitable for `equal'. |
| 4731 | If (equal A B), then (= (sxhash-equal A) (sxhash-equal B)). | 4733 | If (equal A B), then (= (sxhash-equal A) (sxhash-equal B)). |
| 4732 | 4734 | ||
| 4733 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) | 4735 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) |
| @@ -4751,7 +4753,7 @@ keys. Default is `eql'. Predefined are the tests `eq', `eql', and | |||
| 4751 | Default is 65. | 4753 | Default is 65. |
| 4752 | 4754 | ||
| 4753 | :rehash-size REHASH-SIZE - Indicates how to expand the table when it | 4755 | :rehash-size REHASH-SIZE - Indicates how to expand the table when it |
| 4754 | fills up. If REHASH-SIZE is a fixnum, increase the size by that | 4756 | fills up. If REHASH-SIZE is an integer, increase the size by that |
| 4755 | amount. If it is a float, it must be > 1.0, and the new size is the | 4757 | amount. If it is a float, it must be > 1.0, and the new size is the |
| 4756 | old size multiplied by that factor. Default is 1.5. | 4758 | old size multiplied by that factor. Default is 1.5. |
| 4757 | 4759 | ||