aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattias EngdegÄrd2024-01-25 18:56:03 +0100
committerMattias EngdegÄrd2024-01-27 12:37:53 +0100
commitda726c6de201cdb9123bd99e22206dbed5fdc50f (patch)
tree7211aebebf8b41c6aa2206882ae2ed271eba479b /src
parent9b3f43fa08b2672a5ef33b872b2c6d1b0e881b88 (diff)
downloademacs-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.c21
-rw-r--r--src/fns.c7
-rw-r--r--src/lisp.h54
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) \
diff --git a/src/fns.c b/src/fns.c
index 859df6748f7..e4fa8157000 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -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
2634void hash_table_thaw (Lisp_Object hash_table); 2640void hash_table_thaw (Lisp_Object hash_table);
2635 2641