aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fns.c53
-rw-r--r--src/lisp.h12
-rw-r--r--src/pdumper.c63
3 files changed, 70 insertions, 58 deletions
diff --git a/src/fns.c b/src/fns.c
index efec74d4959..74fdf29417e 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -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
4477Lisp_Object 4477static Lisp_Object
4478hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) 4478hashfn_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). 4693static const struct hash_table_test *
4695 Normally there's never a need to recompute hashes. 4694hash_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. */
4699void 4706void
4700hash_table_rehash (Lisp_Object hash) 4707hash_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
2386struct Lisp_Hash_Table; 2386struct Lisp_Hash_Table;
2387 2387
2388typedef enum {
2389 Test_eql,
2390 Test_eq,
2391 Test_equal,
2392} hash_table_std_test_t;
2393
2388struct hash_table_test 2394struct 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
2566void hash_table_rehash (Lisp_Object); 2575void 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);
4038extern char *extract_data_from_object (Lisp_Object, ptrdiff_t *, ptrdiff_t *); 4047extern char *extract_data_from_object (Lisp_Object, ptrdiff_t *, ptrdiff_t *);
4039EMACS_UINT hash_string (char const *, ptrdiff_t); 4048EMACS_UINT hash_string (char const *, ptrdiff_t);
4040EMACS_UINT sxhash (Lisp_Object); 4049EMACS_UINT sxhash (Lisp_Object);
4041Lisp_Object hashfn_user_defined (Lisp_Object, struct Lisp_Hash_Table *);
4042Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, 4050Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT,
4043 hash_table_weakness_t, bool); 4051 hash_table_weakness_t, bool);
4044Lisp_Object hash_table_weakness_symbol (hash_table_weakness_t weak); 4052Lisp_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. */
2651static Lisp_Object 2651static Lisp_Object
2652hash_table_contents (struct Lisp_Hash_Table *h) 2652hash_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
2689static void 2681static hash_table_std_test_t
2690hash_table_freeze (struct Lisp_Hash_Table *h) 2682hash_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. */
2699static void 2697static void
2700hash_table_thaw (Lisp_Object hash) 2698hash_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
2710static dump_off 2709static 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}