diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/fns.c | 53 | ||||
| -rw-r--r-- | src/lisp.h | 12 | ||||
| -rw-r--r-- | src/pdumper.c | 63 |
3 files changed, 70 insertions, 58 deletions
| @@ -4474,7 +4474,7 @@ hashfn_eql (Lisp_Object key, struct Lisp_Hash_Table *h) | |||
| 4474 | /* Given H, return a hash code for KEY which uses a user-defined | 4474 | /* Given H, return a hash code for KEY which uses a user-defined |
| 4475 | function to compare keys. */ | 4475 | function to compare keys. */ |
| 4476 | 4476 | ||
| 4477 | Lisp_Object | 4477 | static Lisp_Object |
| 4478 | hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) | 4478 | hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) |
| 4479 | { | 4479 | { |
| 4480 | Lisp_Object args[] = { h->test.user_hash_function, key }; | 4480 | Lisp_Object args[] = { h->test.user_hash_function, key }; |
| @@ -4638,11 +4638,10 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) | |||
| 4638 | if (h->next_free < 0) | 4638 | if (h->next_free < 0) |
| 4639 | { | 4639 | { |
| 4640 | ptrdiff_t old_size = HASH_TABLE_SIZE (h); | 4640 | ptrdiff_t old_size = HASH_TABLE_SIZE (h); |
| 4641 | EMACS_INT new_size; | 4641 | /* FIXME: better growth management, ditch std_rehash_size */ |
| 4642 | 4642 | EMACS_INT new_size = old_size * std_rehash_size; | |
| 4643 | double float_new_size = old_size * std_rehash_size; | 4643 | if (new_size < EMACS_INT_MAX) |
| 4644 | if (float_new_size < EMACS_INT_MAX) | 4644 | new_size = max (new_size, 32); /* avoid slow initial growth */ |
| 4645 | new_size = float_new_size; | ||
| 4646 | else | 4645 | else |
| 4647 | new_size = EMACS_INT_MAX; | 4646 | new_size = EMACS_INT_MAX; |
| 4648 | if (PTRDIFF_MAX < new_size) | 4647 | if (PTRDIFF_MAX < new_size) |
| @@ -4691,20 +4690,39 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) | |||
| 4691 | } | 4690 | } |
| 4692 | } | 4691 | } |
| 4693 | 4692 | ||
| 4694 | /* Recompute the hashes (and hence also the "next" pointers). | 4693 | static const struct hash_table_test * |
| 4695 | Normally there's never a need to recompute hashes. | 4694 | hash_table_test_from_std (hash_table_std_test_t test) |
| 4696 | This is done only on first access to a hash-table loaded from | 4695 | { |
| 4697 | the "pdump", because the objects' addresses may have changed, thus | 4696 | switch (test) |
| 4698 | affecting their hashes. */ | 4697 | { |
| 4698 | case Test_eq: return &hashtest_eq; | ||
| 4699 | case Test_eql: return &hashtest_eql; | ||
| 4700 | case Test_equal: return &hashtest_equal; | ||
| 4701 | } | ||
| 4702 | emacs_abort(); | ||
| 4703 | } | ||
| 4704 | |||
| 4705 | /* Rebuild a hash table from its frozen (dumped) form. */ | ||
| 4699 | void | 4706 | void |
| 4700 | hash_table_rehash (Lisp_Object hash) | 4707 | hash_table_thaw (Lisp_Object hash_table) |
| 4701 | { | 4708 | { |
| 4702 | struct Lisp_Hash_Table *h = XHASH_TABLE (hash); | 4709 | struct Lisp_Hash_Table *h = XHASH_TABLE (hash_table); |
| 4703 | ptrdiff_t i, count = h->count; | 4710 | |
| 4711 | /* Freezing discarded most non-essential information; recompute it. | ||
| 4712 | The allocation is minimal with no room for growth. */ | ||
| 4713 | h->test = *hash_table_test_from_std (h->frozen_test); | ||
| 4714 | ptrdiff_t size = ASIZE (h->key_and_value) / 2; | ||
| 4715 | h->count = size; | ||
| 4716 | ptrdiff_t index_size = hash_index_size (size); | ||
| 4717 | h->next_free = -1; | ||
| 4718 | |||
| 4719 | h->hash = make_nil_vector (size); | ||
| 4720 | h->next = make_vector (size, make_fixnum (-1)); | ||
| 4721 | h->index = make_vector (index_size, make_fixnum (-1)); | ||
| 4704 | 4722 | ||
| 4705 | /* Recompute the actual hash codes for each entry in the table. | 4723 | /* Recompute the actual hash codes for each entry in the table. |
| 4706 | Order is still invalid. */ | 4724 | Order is still invalid. */ |
| 4707 | for (i = 0; i < count; i++) | 4725 | for (ptrdiff_t i = 0; i < size; i++) |
| 4708 | { | 4726 | { |
| 4709 | Lisp_Object key = HASH_KEY (h, i); | 4727 | Lisp_Object key = HASH_KEY (h, i); |
| 4710 | Lisp_Object hash_code = hash_from_key (h, key); | 4728 | Lisp_Object hash_code = hash_from_key (h, key); |
| @@ -4712,12 +4730,7 @@ hash_table_rehash (Lisp_Object hash) | |||
| 4712 | set_hash_hash_slot (h, i, hash_code); | 4730 | set_hash_hash_slot (h, i, hash_code); |
| 4713 | set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket)); | 4731 | set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket)); |
| 4714 | set_hash_index_slot (h, start_of_bucket, i); | 4732 | set_hash_index_slot (h, start_of_bucket, i); |
| 4715 | eassert (HASH_NEXT (h, i) != i); /* Stop loops. */ | ||
| 4716 | } | 4733 | } |
| 4717 | |||
| 4718 | ptrdiff_t size = ASIZE (h->next); | ||
| 4719 | for (; i + 1 < size; i++) | ||
| 4720 | set_hash_next_slot (h, i, i + 1); | ||
| 4721 | } | 4734 | } |
| 4722 | 4735 | ||
| 4723 | /* Lookup KEY in hash table H. If HASH is non-null, return in *HASH | 4736 | /* Lookup KEY in hash table H. If HASH is non-null, return in *HASH |
diff --git a/src/lisp.h b/src/lisp.h index 48e1f943ed8..d9b828b0328 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2385,6 +2385,12 @@ INLINE int | |||
| 2385 | 2385 | ||
| 2386 | struct Lisp_Hash_Table; | 2386 | struct Lisp_Hash_Table; |
| 2387 | 2387 | ||
| 2388 | typedef enum { | ||
| 2389 | Test_eql, | ||
| 2390 | Test_eq, | ||
| 2391 | Test_equal, | ||
| 2392 | } hash_table_std_test_t; | ||
| 2393 | |||
| 2388 | struct hash_table_test | 2394 | struct hash_table_test |
| 2389 | { | 2395 | { |
| 2390 | /* Function used to compare keys; always a bare symbol. */ | 2396 | /* Function used to compare keys; always a bare symbol. */ |
| @@ -2473,6 +2479,9 @@ struct Lisp_Hash_Table | |||
| 2473 | /* Weakness of the table. */ | 2479 | /* Weakness of the table. */ |
| 2474 | hash_table_weakness_t weakness : 8; | 2480 | hash_table_weakness_t weakness : 8; |
| 2475 | 2481 | ||
| 2482 | /* Hash table test (only used when frozen in dump) */ | ||
| 2483 | hash_table_std_test_t frozen_test : 8; | ||
| 2484 | |||
| 2476 | /* True if the table can be purecopied. The table cannot be | 2485 | /* True if the table can be purecopied. The table cannot be |
| 2477 | changed afterwards. */ | 2486 | changed afterwards. */ |
| 2478 | bool purecopy; | 2487 | bool purecopy; |
| @@ -2563,7 +2572,7 @@ hash_from_key (struct Lisp_Hash_Table *h, Lisp_Object key) | |||
| 2563 | return h->test.hashfn (key, h); | 2572 | return h->test.hashfn (key, h); |
| 2564 | } | 2573 | } |
| 2565 | 2574 | ||
| 2566 | void hash_table_rehash (Lisp_Object); | 2575 | void hash_table_thaw (Lisp_Object hash_table); |
| 2567 | 2576 | ||
| 2568 | /* Default size for hash tables if not specified. */ | 2577 | /* Default size for hash tables if not specified. */ |
| 2569 | 2578 | ||
| @@ -4038,7 +4047,6 @@ extern void hexbuf_digest (char *, void const *, int); | |||
| 4038 | extern char *extract_data_from_object (Lisp_Object, ptrdiff_t *, ptrdiff_t *); | 4047 | extern char *extract_data_from_object (Lisp_Object, ptrdiff_t *, ptrdiff_t *); |
| 4039 | EMACS_UINT hash_string (char const *, ptrdiff_t); | 4048 | EMACS_UINT hash_string (char const *, ptrdiff_t); |
| 4040 | EMACS_UINT sxhash (Lisp_Object); | 4049 | EMACS_UINT sxhash (Lisp_Object); |
| 4041 | Lisp_Object hashfn_user_defined (Lisp_Object, struct Lisp_Hash_Table *); | ||
| 4042 | Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, | 4050 | Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, |
| 4043 | hash_table_weakness_t, bool); | 4051 | hash_table_weakness_t, bool); |
| 4044 | Lisp_Object hash_table_weakness_symbol (hash_table_weakness_t weak); | 4052 | Lisp_Object hash_table_weakness_symbol (hash_table_weakness_t weak); |
diff --git a/src/pdumper.c b/src/pdumper.c index 8072148c542..e4349f0cb17 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -2646,34 +2646,26 @@ dump_vectorlike_generic (struct dump_context *ctx, | |||
| 2646 | return offset; | 2646 | return offset; |
| 2647 | } | 2647 | } |
| 2648 | 2648 | ||
| 2649 | /* Return a vector of KEY, VALUE pairs in the given hash table H. The | 2649 | /* Return a vector of KEY, VALUE pairs in the given hash table H. |
| 2650 | first H->count pairs are valid, and the rest are unbound. */ | 2650 | No room for growth is included. */ |
| 2651 | static Lisp_Object | 2651 | static Lisp_Object |
| 2652 | hash_table_contents (struct Lisp_Hash_Table *h) | 2652 | hash_table_contents (struct Lisp_Hash_Table *h) |
| 2653 | { | 2653 | { |
| 2654 | if (h->test.hashfn == hashfn_user_defined) | 2654 | ptrdiff_t old_size = HASH_TABLE_SIZE (h); |
| 2655 | error ("cannot dump hash tables with user-defined tests"); /* Bug#36769 */ | 2655 | ptrdiff_t size = h->count; |
| 2656 | |||
| 2657 | ptrdiff_t size = HASH_TABLE_SIZE (h); | ||
| 2658 | Lisp_Object key_and_value = make_uninit_vector (2 * size); | 2656 | Lisp_Object key_and_value = make_uninit_vector (2 * size); |
| 2659 | ptrdiff_t n = 0; | 2657 | ptrdiff_t n = 0; |
| 2660 | 2658 | ||
| 2661 | /* Make sure key_and_value ends up in the same order; charset.c | 2659 | /* Make sure key_and_value ends up in the same order; charset.c |
| 2662 | relies on it by expecting hash table indices to stay constant | 2660 | relies on it by expecting hash table indices to stay constant |
| 2663 | across the dump. */ | 2661 | across the dump. */ |
| 2664 | for (ptrdiff_t i = 0; i < size; i++) | 2662 | for (ptrdiff_t i = 0; i < old_size; i++) |
| 2665 | if (!NILP (HASH_HASH (h, i))) | 2663 | if (!NILP (HASH_HASH (h, i))) |
| 2666 | { | 2664 | { |
| 2667 | ASET (key_and_value, n++, HASH_KEY (h, i)); | 2665 | ASET (key_and_value, n++, HASH_KEY (h, i)); |
| 2668 | ASET (key_and_value, n++, HASH_VALUE (h, i)); | 2666 | ASET (key_and_value, n++, HASH_VALUE (h, i)); |
| 2669 | } | 2667 | } |
| 2670 | 2668 | ||
| 2671 | while (n < 2 * size) | ||
| 2672 | { | ||
| 2673 | ASET (key_and_value, n++, Qunbound); | ||
| 2674 | ASET (key_and_value, n++, Qnil); | ||
| 2675 | } | ||
| 2676 | |||
| 2677 | return key_and_value; | 2669 | return key_and_value; |
| 2678 | } | 2670 | } |
| 2679 | 2671 | ||
| @@ -2686,25 +2678,32 @@ dump_hash_table_list (struct dump_context *ctx) | |||
| 2686 | return 0; | 2678 | return 0; |
| 2687 | } | 2679 | } |
| 2688 | 2680 | ||
| 2689 | static void | 2681 | static hash_table_std_test_t |
| 2690 | hash_table_freeze (struct Lisp_Hash_Table *h) | 2682 | hash_table_std_test (const struct hash_table_test *t) |
| 2691 | { | 2683 | { |
| 2692 | ptrdiff_t npairs = ASIZE (h->key_and_value) / 2; | 2684 | if (BASE_EQ (t->name, Qeq)) |
| 2693 | h->key_and_value = hash_table_contents (h); | 2685 | return Test_eq; |
| 2694 | h->next = h->hash = make_fixnum (npairs); | 2686 | if (BASE_EQ (t->name, Qeql)) |
| 2695 | h->index = make_fixnum (ASIZE (h->index)); | 2687 | return Test_eql; |
| 2696 | h->next_free = (npairs == h->count ? -1 : h->count); | 2688 | if (BASE_EQ (t->name, Qequal)) |
| 2689 | return Test_equal; | ||
| 2690 | error ("cannot dump hash tables with user-defined tests"); /* Bug#36769 */ | ||
| 2697 | } | 2691 | } |
| 2698 | 2692 | ||
| 2693 | /* Compact contents and discard inessential information from a hash table, | ||
| 2694 | preparing it for dumping. | ||
| 2695 | See `hash_table_thaw' for the code that restores the object to a usable | ||
| 2696 | state. */ | ||
| 2699 | static void | 2697 | static void |
| 2700 | hash_table_thaw (Lisp_Object hash) | 2698 | hash_table_freeze (struct Lisp_Hash_Table *h) |
| 2701 | { | 2699 | { |
| 2702 | struct Lisp_Hash_Table *h = XHASH_TABLE (hash); | 2700 | h->key_and_value = hash_table_contents (h); |
| 2703 | h->hash = make_nil_vector (XFIXNUM (h->hash)); | 2701 | eassert (ASIZE (h->key_and_value) == h->count * 2); |
| 2704 | h->next = Fmake_vector (h->next, make_fixnum (-1)); | 2702 | h->next = Qnil; |
| 2705 | h->index = Fmake_vector (h->index, make_fixnum (-1)); | 2703 | h->hash = Qnil; |
| 2706 | 2704 | h->index = Qnil; | |
| 2707 | hash_table_rehash (hash); | 2705 | h->count = 0; |
| 2706 | h->frozen_test = hash_table_std_test (&h->test); | ||
| 2708 | } | 2707 | } |
| 2709 | 2708 | ||
| 2710 | static dump_off | 2709 | static dump_off |
| @@ -2724,19 +2723,11 @@ dump_hash_table (struct dump_context *ctx, Lisp_Object object) | |||
| 2724 | dump_pseudovector_lisp_fields (ctx, &out->header, &hash->header); | 2723 | dump_pseudovector_lisp_fields (ctx, &out->header, &hash->header); |
| 2725 | /* TODO: dump the hash bucket vectors synchronously here to keep | 2724 | /* TODO: dump the hash bucket vectors synchronously here to keep |
| 2726 | them as close to the hash table as possible. */ | 2725 | them as close to the hash table as possible. */ |
| 2727 | DUMP_FIELD_COPY (out, hash, count); | ||
| 2728 | DUMP_FIELD_COPY (out, hash, next_free); | ||
| 2729 | DUMP_FIELD_COPY (out, hash, weakness); | 2726 | DUMP_FIELD_COPY (out, hash, weakness); |
| 2730 | DUMP_FIELD_COPY (out, hash, purecopy); | 2727 | DUMP_FIELD_COPY (out, hash, purecopy); |
| 2731 | DUMP_FIELD_COPY (out, hash, mutable); | 2728 | DUMP_FIELD_COPY (out, hash, mutable); |
| 2729 | DUMP_FIELD_COPY (out, hash, frozen_test); | ||
| 2732 | dump_field_lv (ctx, out, hash, &hash->key_and_value, WEIGHT_STRONG); | 2730 | dump_field_lv (ctx, out, hash, &hash->key_and_value, WEIGHT_STRONG); |
| 2733 | dump_field_lv (ctx, out, hash, &hash->test.name, WEIGHT_STRONG); | ||
| 2734 | dump_field_lv (ctx, out, hash, &hash->test.user_hash_function, | ||
| 2735 | WEIGHT_STRONG); | ||
| 2736 | dump_field_lv (ctx, out, hash, &hash->test.user_cmp_function, | ||
| 2737 | WEIGHT_STRONG); | ||
| 2738 | dump_field_emacs_ptr (ctx, out, hash, &hash->test.cmpfn); | ||
| 2739 | dump_field_emacs_ptr (ctx, out, hash, &hash->test.hashfn); | ||
| 2740 | eassert (hash->next_weak == NULL); | 2731 | eassert (hash->next_weak == NULL); |
| 2741 | return finish_dump_pvec (ctx, &out->header); | 2732 | return finish_dump_pvec (ctx, &out->header); |
| 2742 | } | 2733 | } |