diff options
| author | Mattias EngdegÄrd | 2024-01-25 18:56:03 +0100 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2024-01-27 12:37:53 +0100 |
| commit | da726c6de201cdb9123bd99e22206dbed5fdc50f (patch) | |
| tree | 7211aebebf8b41c6aa2206882ae2ed271eba479b /src | |
| parent | 9b3f43fa08b2672a5ef33b872b2c6d1b0e881b88 (diff) | |
| download | emacs-da726c6de201cdb9123bd99e22206dbed5fdc50f.tar.gz emacs-da726c6de201cdb9123bd99e22206dbed5fdc50f.zip | |
Add DOHASH_SAFE, make DOHASH faster (bug#68690)
Revert DOHASH to the fast (field-caching) implementation but with
an assertion to detect misuses. Add DOHASH_SAFE for use in
code that must tolerate arbitrary mutation of the table being
iterated through.
* src/lisp.h (DOHASH): Go back to fast design that only allows
restricted mutation, but with a checking assertion.
(DOHASH_SAFE): New macro that tolerates arbitrary mutation while being
much simpler (and acceptably fast).
* src/fns.c (Fmaphash):
* src/comp.c (compile_function, Fcomp__compile_ctxt_to_file):
Use DOHASH_SAFE.
Diffstat (limited to 'src')
| -rw-r--r-- | src/comp.c | 21 | ||||
| -rw-r--r-- | src/fns.c | 7 | ||||
| -rw-r--r-- | src/lisp.h | 54 |
3 files changed, 48 insertions, 34 deletions
diff --git a/src/comp.c b/src/comp.c index 5f28cf046b5..853757f6162 100644 --- a/src/comp.c +++ b/src/comp.c | |||
| @@ -4330,9 +4330,12 @@ compile_function (Lisp_Object func) | |||
| 4330 | declare_block (Qentry); | 4330 | declare_block (Qentry); |
| 4331 | Lisp_Object blocks = CALL1I (comp-func-blocks, func); | 4331 | Lisp_Object blocks = CALL1I (comp-func-blocks, func); |
| 4332 | struct Lisp_Hash_Table *ht = XHASH_TABLE (blocks); | 4332 | struct Lisp_Hash_Table *ht = XHASH_TABLE (blocks); |
| 4333 | DOHASH (ht, block_name, block) | 4333 | DOHASH_SAFE (ht, i) |
| 4334 | if (!EQ (block_name, Qentry)) | 4334 | { |
| 4335 | declare_block (block_name); | 4335 | Lisp_Object block_name = HASH_KEY (ht, i); |
| 4336 | if (!EQ (block_name, Qentry)) | ||
| 4337 | declare_block (block_name); | ||
| 4338 | } | ||
| 4336 | 4339 | ||
| 4337 | gcc_jit_block_add_assignment (retrive_block (Qentry), | 4340 | gcc_jit_block_add_assignment (retrive_block (Qentry), |
| 4338 | NULL, | 4341 | NULL, |
| @@ -4340,8 +4343,10 @@ compile_function (Lisp_Object func) | |||
| 4340 | gcc_jit_lvalue_as_rvalue (comp.func_relocs)); | 4343 | gcc_jit_lvalue_as_rvalue (comp.func_relocs)); |
| 4341 | 4344 | ||
| 4342 | 4345 | ||
| 4343 | DOHASH (ht, block_name, block) | 4346 | DOHASH_SAFE (ht, i) |
| 4344 | { | 4347 | { |
| 4348 | Lisp_Object block_name = HASH_KEY (ht, i); | ||
| 4349 | Lisp_Object block = HASH_VALUE (ht, i); | ||
| 4345 | Lisp_Object insns = CALL1I (comp-block-insns, block); | 4350 | Lisp_Object insns = CALL1I (comp-block-insns, block); |
| 4346 | if (NILP (block) || NILP (insns)) | 4351 | if (NILP (block) || NILP (insns)) |
| 4347 | xsignal1 (Qnative_ice, | 4352 | xsignal1 (Qnative_ice, |
| @@ -4956,12 +4961,12 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file, | |||
| 4956 | 4961 | ||
| 4957 | struct Lisp_Hash_Table *func_h = | 4962 | struct Lisp_Hash_Table *func_h = |
| 4958 | XHASH_TABLE (CALL1I (comp-ctxt-funcs-h, Vcomp_ctxt)); | 4963 | XHASH_TABLE (CALL1I (comp-ctxt-funcs-h, Vcomp_ctxt)); |
| 4959 | DOHASH (func_h, k, v) | 4964 | DOHASH_SAFE (func_h, i) |
| 4960 | declare_function (v); | 4965 | declare_function (HASH_VALUE (func_h, i)); |
| 4961 | /* Compile all functions. Can't be done before because the | 4966 | /* Compile all functions. Can't be done before because the |
| 4962 | relocation structs has to be already defined. */ | 4967 | relocation structs has to be already defined. */ |
| 4963 | DOHASH (func_h, k, v) | 4968 | DOHASH_SAFE (func_h, i) |
| 4964 | compile_function (v); | 4969 | compile_function (HASH_VALUE (func_h, i)); |
| 4965 | 4970 | ||
| 4966 | /* Work around bug#46495 (GCC PR99126). */ | 4971 | /* Work around bug#46495 (GCC PR99126). */ |
| 4967 | #if defined (WIDE_EMACS_INT) \ | 4972 | #if defined (WIDE_EMACS_INT) \ |
| @@ -5662,8 +5662,11 @@ set a new value for KEY, or `remhash' to remove KEY. | |||
| 5662 | (Lisp_Object function, Lisp_Object table) | 5662 | (Lisp_Object function, Lisp_Object table) |
| 5663 | { | 5663 | { |
| 5664 | struct Lisp_Hash_Table *h = check_hash_table (table); | 5664 | struct Lisp_Hash_Table *h = check_hash_table (table); |
| 5665 | DOHASH (h, k, v) | 5665 | /* We can't use DOHASH here since FUNCTION may violate the rules and |
| 5666 | call2 (function, k, v); | 5666 | we shouldn't crash as a result (although the effects are |
| 5667 | unpredictable). */ | ||
| 5668 | DOHASH_SAFE (h, i) | ||
| 5669 | call2 (function, HASH_KEY (h, i), HASH_VALUE (h, i)); | ||
| 5667 | return Qnil; | 5670 | return Qnil; |
| 5668 | } | 5671 | } |
| 5669 | 5672 | ||
diff --git a/src/lisp.h b/src/lisp.h index d07d9d14e2f..c2dfd1afad5 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2604,32 +2604,38 @@ hash_from_key (struct Lisp_Hash_Table *h, Lisp_Object key) | |||
| 2604 | } | 2604 | } |
| 2605 | 2605 | ||
| 2606 | /* Iterate K and V as key and value of valid entries in hash table H. | 2606 | /* Iterate K and V as key and value of valid entries in hash table H. |
| 2607 | The body may mutate the hash-table. */ | 2607 | The body may remove the current entry or alter its value slot, but not |
| 2608 | #define DOHASH(h, k, v) \ | 2608 | mutate TABLE in any other way. */ |
| 2609 | for (Lisp_Object *dohash_##k##_##v##_base = (h)->key_and_value, \ | 2609 | #define DOHASH(h, k, v) \ |
| 2610 | *dohash_##k##_##v##_kv = dohash_##k##_##v##_base, \ | 2610 | for (Lisp_Object *dohash_##k##_##v##_kv = (h)->key_and_value, \ |
| 2611 | *dohash_##k##_##v##_end = dohash_##k##_##v##_base \ | 2611 | *dohash_##k##_##v##_end = dohash_##k##_##v##_kv \ |
| 2612 | + 2 * HASH_TABLE_SIZE (h), \ | 2612 | + 2 * HASH_TABLE_SIZE (h), \ |
| 2613 | k, v; \ | 2613 | *dohash_##k##_##v##_base = dohash_##k##_##v##_kv, \ |
| 2614 | dohash_##k##_##v##_kv < dohash_##k##_##v##_end \ | 2614 | k, v; \ |
| 2615 | && (dohash_##k##_##v##_base == (h)->key_and_value \ | 2615 | dohash_##k##_##v##_kv < dohash_##k##_##v##_end \ |
| 2616 | /* The `key_and_value` table has been reallocated! */ \ | 2616 | && (k = dohash_##k##_##v##_kv[0], \ |
| 2617 | || (dohash_##k##_##v##_kv \ | 2617 | v = dohash_##k##_##v##_kv[1], /*maybe unused*/ (void)v, \ |
| 2618 | = (dohash_##k##_##v##_kv - dohash_##k##_##v##_base) \ | 2618 | true); \ |
| 2619 | + (h)->key_and_value, \ | 2619 | eassert (dohash_##k##_##v##_base == (h)->key_and_value \ |
| 2620 | dohash_##k##_##v##_base = (h)->key_and_value, \ | 2620 | && dohash_##k##_##v##_end \ |
| 2621 | dohash_##k##_##v##_end = dohash_##k##_##v##_base \ | 2621 | == dohash_##k##_##v##_base \ |
| 2622 | + 2 * HASH_TABLE_SIZE (h), \ | 2622 | + 2 * HASH_TABLE_SIZE (h)), \ |
| 2623 | /* Check again, in case the table has shrunk. */ \ | 2623 | dohash_##k##_##v##_kv += 2) \ |
| 2624 | dohash_##k##_##v##_kv < dohash_##k##_##v##_end)) \ | 2624 | if (hash_unused_entry_key_p (k)) \ |
| 2625 | && (k = dohash_##k##_##v##_kv[0], \ | 2625 | ; \ |
| 2626 | v = dohash_##k##_##v##_kv[1], /*maybe unused*/ (void)v, \ | ||
| 2627 | true); \ | ||
| 2628 | dohash_##k##_##v##_kv += 2) \ | ||
| 2629 | if (hash_unused_entry_key_p (k)) \ | ||
| 2630 | ; \ | ||
| 2631 | else | 2626 | else |
| 2632 | 2627 | ||
| 2628 | /* Iterate I as index of valid entries in hash table H. | ||
| 2629 | Unlike DOHASH, this construct copes with arbitrary table mutations | ||
| 2630 | in the body. The consequences of such mutations are limited to | ||
| 2631 | whether and in what order entries are encountered by the loop | ||
| 2632 | (which is usually bad enough), but not crashing or corrupting the | ||
| 2633 | Lisp state. */ | ||
| 2634 | #define DOHASH_SAFE(h, i) \ | ||
| 2635 | for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); i++) \ | ||
| 2636 | if (hash_unused_entry_key_p (HASH_KEY (h, i))) \ | ||
| 2637 | ; \ | ||
| 2638 | else | ||
| 2633 | 2639 | ||
| 2634 | void hash_table_thaw (Lisp_Object hash_table); | 2640 | void hash_table_thaw (Lisp_Object hash_table); |
| 2635 | 2641 | ||