summaryrefslogtreecommitdiff
path: root/src/lisp.h
diff options
context:
space:
mode:
authorMattias EngdegÄrd <mattiase@acm.org>2024-01-25 18:56:03 +0100
committerMattias EngdegÄrd <mattiase@acm.org>2024-01-27 12:37:53 +0100
commitda726c6de201cdb9123bd99e22206dbed5fdc50f (patch)
tree7211aebebf8b41c6aa2206882ae2ed271eba479b /src/lisp.h
parent9b3f43fa08b2672a5ef33b872b2c6d1b0e881b88 (diff)
downloademacs-da726c6de201cdb9123bd99e22206dbed5fdc50f.tar.gz
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/lisp.h')
-rw-r--r--src/lisp.h54
1 files changed, 30 insertions, 24 deletions
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)
}
/* Iterate K and V as key and value of valid entries in hash table H.
- The body may mutate the hash-table. */
-#define DOHASH(h, k, v) \
- for (Lisp_Object *dohash_##k##_##v##_base = (h)->key_and_value, \
- *dohash_##k##_##v##_kv = dohash_##k##_##v##_base, \
- *dohash_##k##_##v##_end = dohash_##k##_##v##_base \
- + 2 * HASH_TABLE_SIZE (h), \
- k, v; \
- dohash_##k##_##v##_kv < dohash_##k##_##v##_end \
- && (dohash_##k##_##v##_base == (h)->key_and_value \
- /* The `key_and_value` table has been reallocated! */ \
- || (dohash_##k##_##v##_kv \
- = (dohash_##k##_##v##_kv - dohash_##k##_##v##_base) \
- + (h)->key_and_value, \
- dohash_##k##_##v##_base = (h)->key_and_value, \
- dohash_##k##_##v##_end = dohash_##k##_##v##_base \
- + 2 * HASH_TABLE_SIZE (h), \
- /* Check again, in case the table has shrunk. */ \
- dohash_##k##_##v##_kv < dohash_##k##_##v##_end)) \
- && (k = dohash_##k##_##v##_kv[0], \
- v = dohash_##k##_##v##_kv[1], /*maybe unused*/ (void)v, \
- true); \
- dohash_##k##_##v##_kv += 2) \
- if (hash_unused_entry_key_p (k)) \
- ; \
+ The body may remove the current entry or alter its value slot, but not
+ mutate TABLE in any other way. */
+#define DOHASH(h, k, v) \
+ for (Lisp_Object *dohash_##k##_##v##_kv = (h)->key_and_value, \
+ *dohash_##k##_##v##_end = dohash_##k##_##v##_kv \
+ + 2 * HASH_TABLE_SIZE (h), \
+ *dohash_##k##_##v##_base = dohash_##k##_##v##_kv, \
+ k, v; \
+ dohash_##k##_##v##_kv < dohash_##k##_##v##_end \
+ && (k = dohash_##k##_##v##_kv[0], \
+ v = dohash_##k##_##v##_kv[1], /*maybe unused*/ (void)v, \
+ true); \
+ eassert (dohash_##k##_##v##_base == (h)->key_and_value \
+ && dohash_##k##_##v##_end \
+ == dohash_##k##_##v##_base \
+ + 2 * HASH_TABLE_SIZE (h)), \
+ dohash_##k##_##v##_kv += 2) \
+ if (hash_unused_entry_key_p (k)) \
+ ; \
else
+/* Iterate I as index of valid entries in hash table H.
+ Unlike DOHASH, this construct copes with arbitrary table mutations
+ in the body. The consequences of such mutations are limited to
+ whether and in what order entries are encountered by the loop
+ (which is usually bad enough), but not crashing or corrupting the
+ Lisp state. */
+#define DOHASH_SAFE(h, i) \
+ for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); i++) \
+ if (hash_unused_entry_key_p (HASH_KEY (h, i))) \
+ ; \
+ else
void hash_table_thaw (Lisp_Object hash_table);