diff options
| author | Mattias EngdegÄrd | 2023-11-04 16:34:09 +0100 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2024-01-13 20:50:37 +0100 |
| commit | d3cefd3e98354929d96c9396e5920e8a123784dc (patch) | |
| tree | b0fd45c15faa88216653413229e759444810585d /src/fns.c | |
| parent | c3d0cc50faf588479db62e20ceabe044dd89e244 (diff) | |
| download | emacs-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.c | 53 |
1 files changed, 33 insertions, 20 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 |