aboutsummaryrefslogtreecommitdiffstats
path: root/src/fns.c
diff options
context:
space:
mode:
authorMattias EngdegÄrd2023-11-04 16:34:09 +0100
committerMattias EngdegÄrd2024-01-13 20:50:37 +0100
commitd3cefd3e98354929d96c9396e5920e8a123784dc (patch)
treeb0fd45c15faa88216653413229e759444810585d /src/fns.c
parentc3d0cc50faf588479db62e20ceabe044dd89e244 (diff)
downloademacs-d3cefd3e98354929d96c9396e5920e8a123784dc.tar.gz
emacs-d3cefd3e98354929d96c9396e5920e8a123784dc.zip
Leaner hash table dumping and thawing
Only dump the actual data, and the test encoded as an enum. This simplifies dumping, makes dump files smaller and saves space at run time. * src/lisp.h (hash_table_std_test_t): New enum. (struct Lisp_Hash_Table): Add frozen_test member, consuming no extra space. * src/fns.c (hashfn_user_defined): Now static. (hash_table_test_from_std): New. (hash_table_rehash): Rename to... (hash_table_thaw): ...this and rewrite. * src/pdumper.c (hash_table_contents): Only include actual data, not unused space. (hash_table_std_test): New. (hash_table_freeze): Set frozen_test from test. (dump_hash_table): Dump frozen_test, not the whole test struct. Don't bother other dumping fields that can be derived.
Diffstat (limited to 'src/fns.c')
-rw-r--r--src/fns.c53
1 files changed, 33 insertions, 20 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