diff options
| author | Mattias EngdegÄrd | 2025-09-16 18:57:51 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2025-09-17 12:49:14 +0200 |
| commit | de4ca2bdb1ae69a6ad0c4fc0473f2823e74f7f2b (patch) | |
| tree | b9222093ec43a83656dc94bb1a8e75ce1d0799ae | |
| parent | 08b2d53e48fc8f8081bfa5fe5465dc99dbb7407d (diff) | |
| download | emacs-de4ca2bdb1ae69a6ad0c4fc0473f2823e74f7f2b.tar.gz emacs-de4ca2bdb1ae69a6ad0c4fc0473f2823e74f7f2b.zip | |
Turn some checking macros into functions in the GC marker code
This rids us of a bunch of unhygienic macros with free variables and
makes the marking code actually readable again. Even better, it is all
processed by the compiler even when the checks are disabled.
* src/alloc.c (CHECK_ALLOCATED, CHECK_LIVE, CHECK_ALLOCATED_AND_LIVE)
(CHECK_ALLOCATED_AND_LIVE_SYMBOL): Transform macros into...
(check_live, check_allocated_and_live, check_allocated_and_live_symbol)
(check_allocated_and_live_vectorlike): ...functions. Callers adapted.
| -rw-r--r-- | src/alloc.c | 161 |
1 files changed, 80 insertions, 81 deletions
diff --git a/src/alloc.c b/src/alloc.c index 9ace6f01856..4ed76d9d368 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -120,6 +120,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 120 | #if defined ENABLE_CHECKING && !defined GC_CHECK_MARKED_OBJECTS | 120 | #if defined ENABLE_CHECKING && !defined GC_CHECK_MARKED_OBJECTS |
| 121 | # define GC_CHECK_MARKED_OBJECTS 1 | 121 | # define GC_CHECK_MARKED_OBJECTS 1 |
| 122 | #endif | 122 | #endif |
| 123 | #ifndef GC_CHECK_MARKED_OBJECTS | ||
| 124 | # define GC_CHECK_MARKED_OBJECTS 0 | ||
| 125 | #endif | ||
| 123 | 126 | ||
| 124 | /* GC_MALLOC_CHECK defined means perform validity checks of malloc'd | 127 | /* GC_MALLOC_CHECK defined means perform validity checks of malloc'd |
| 125 | memory. Can do this only if using gmalloc.c and if not checking | 128 | memory. Can do this only if using gmalloc.c and if not checking |
| @@ -6389,6 +6392,75 @@ mark_stack_push_values (Lisp_Object *values, ptrdiff_t n) | |||
| 6389 | .u.values = values}; | 6392 | .u.values = values}; |
| 6390 | } | 6393 | } |
| 6391 | 6394 | ||
| 6395 | /* When GC_CHECK_MARKED_OBJECTS is set, perform some sanity checks on | ||
| 6396 | the objects marked here. Abort if we encounter an object we know is | ||
| 6397 | bogus. This increases GC time by ~80%. */ | ||
| 6398 | |||
| 6399 | /* Check that the object pointed to by PO is alive, using predicate | ||
| 6400 | function LIVEP. */ | ||
| 6401 | static inline void | ||
| 6402 | check_live (bool (*livep) (struct mem_node *m, void *p), enum mem_type mtype, | ||
| 6403 | void *po, struct mem_node *m) | ||
| 6404 | { | ||
| 6405 | if (GC_CHECK_MARKED_OBJECTS) | ||
| 6406 | { | ||
| 6407 | if (pdumper_object_p (po)) | ||
| 6408 | return; | ||
| 6409 | if (!(m->type == mtype && livep (m, po))) | ||
| 6410 | emacs_abort (); | ||
| 6411 | } | ||
| 6412 | } | ||
| 6413 | |||
| 6414 | /* Check that the object pointed to by PO is known to be a Lisp | ||
| 6415 | structure allocated from the heap, and that it is alive. */ | ||
| 6416 | static inline void | ||
| 6417 | check_allocated_and_live (bool (*livep) (struct mem_node *m, void *p), | ||
| 6418 | enum mem_type mtype, | ||
| 6419 | void *po) | ||
| 6420 | { | ||
| 6421 | if (GC_CHECK_MARKED_OBJECTS) | ||
| 6422 | { | ||
| 6423 | if (pdumper_object_p (po)) | ||
| 6424 | { | ||
| 6425 | if (!pdumper_object_p_precise (po)) | ||
| 6426 | emacs_abort (); | ||
| 6427 | return; | ||
| 6428 | } | ||
| 6429 | struct mem_node *m = mem_find (po); | ||
| 6430 | if (m == MEM_NIL) | ||
| 6431 | emacs_abort (); | ||
| 6432 | check_live (livep, mtype, po, m); | ||
| 6433 | } | ||
| 6434 | } | ||
| 6435 | |||
| 6436 | /* Like check_allocated_and_live but for symbols. */ | ||
| 6437 | static inline void | ||
| 6438 | check_allocated_and_live_symbol (void *po, struct Lisp_Symbol *sym) | ||
| 6439 | { | ||
| 6440 | if (GC_CHECK_MARKED_OBJECTS) | ||
| 6441 | if (!c_symbol_p (sym)) | ||
| 6442 | check_allocated_and_live (live_symbol_p, MEM_TYPE_SYMBOL, po); | ||
| 6443 | } | ||
| 6444 | |||
| 6445 | /* Like check_allocated_and_live but for vectorlike. */ | ||
| 6446 | static inline void | ||
| 6447 | check_allocated_and_live_vectorlike (void *po, Lisp_Object obj) | ||
| 6448 | { | ||
| 6449 | if (GC_CHECK_MARKED_OBJECTS) | ||
| 6450 | { | ||
| 6451 | if (!pdumper_object_p (po) && !SUBRP (obj) && !main_thread_p (po)) | ||
| 6452 | { | ||
| 6453 | struct mem_node *m = mem_find (po); | ||
| 6454 | if (m == MEM_NIL) | ||
| 6455 | emacs_abort (); | ||
| 6456 | if (m->type == MEM_TYPE_VECTORLIKE) | ||
| 6457 | check_live (live_large_vector_p, MEM_TYPE_VECTORLIKE, po, m); | ||
| 6458 | else | ||
| 6459 | check_live (live_small_vector_p, MEM_TYPE_VECTOR_BLOCK, po, m); | ||
| 6460 | } | ||
| 6461 | } | ||
| 6462 | } | ||
| 6463 | |||
| 6392 | /* Traverse and mark objects on the mark stack above BASE_SP. | 6464 | /* Traverse and mark objects on the mark stack above BASE_SP. |
| 6393 | 6465 | ||
| 6394 | Traversal is depth-first using the mark stack for most common | 6466 | Traversal is depth-first using the mark stack for most common |
| @@ -6397,9 +6469,6 @@ mark_stack_push_values (Lisp_Object *values, ptrdiff_t n) | |||
| 6397 | static void | 6469 | static void |
| 6398 | process_mark_stack (ptrdiff_t base_sp) | 6470 | process_mark_stack (ptrdiff_t base_sp) |
| 6399 | { | 6471 | { |
| 6400 | #if GC_CHECK_MARKED_OBJECTS | ||
| 6401 | struct mem_node *m = NULL; | ||
| 6402 | #endif | ||
| 6403 | #if GC_CDR_COUNT | 6472 | #if GC_CDR_COUNT |
| 6404 | ptrdiff_t cdr_count = 0; | 6473 | ptrdiff_t cdr_count = 0; |
| 6405 | #endif | 6474 | #endif |
| @@ -6410,66 +6479,12 @@ process_mark_stack (ptrdiff_t base_sp) | |||
| 6410 | { | 6479 | { |
| 6411 | Lisp_Object obj = mark_stack_pop (); | 6480 | Lisp_Object obj = mark_stack_pop (); |
| 6412 | mark_obj: ; | 6481 | mark_obj: ; |
| 6482 | void *po = XPNTR (obj); | ||
| 6413 | #if GC_REMEMBER_LAST_MARKED | 6483 | #if GC_REMEMBER_LAST_MARKED |
| 6414 | last_marked[last_marked_index++] = obj; | 6484 | last_marked[last_marked_index++] = obj; |
| 6415 | last_marked_index &= LAST_MARKED_SIZE - 1; | 6485 | last_marked_index &= LAST_MARKED_SIZE - 1; |
| 6416 | #endif | 6486 | #endif |
| 6417 | 6487 | ||
| 6418 | /* Perform some sanity checks on the objects marked here. Abort if | ||
| 6419 | we encounter an object we know is bogus. This increases GC time | ||
| 6420 | by ~80%. */ | ||
| 6421 | #if GC_CHECK_MARKED_OBJECTS | ||
| 6422 | void *po = XPNTR (obj); | ||
| 6423 | |||
| 6424 | /* Check that the object pointed to by PO is known to be a Lisp | ||
| 6425 | structure allocated from the heap. */ | ||
| 6426 | #define CHECK_ALLOCATED() \ | ||
| 6427 | do { \ | ||
| 6428 | if (pdumper_object_p (po)) \ | ||
| 6429 | { \ | ||
| 6430 | if (!pdumper_object_p_precise (po)) \ | ||
| 6431 | emacs_abort (); \ | ||
| 6432 | break; \ | ||
| 6433 | } \ | ||
| 6434 | m = mem_find (po); \ | ||
| 6435 | if (m == MEM_NIL) \ | ||
| 6436 | emacs_abort (); \ | ||
| 6437 | } while (0) | ||
| 6438 | |||
| 6439 | /* Check that the object pointed to by PO is live, using predicate | ||
| 6440 | function LIVEP. */ | ||
| 6441 | #define CHECK_LIVE(LIVEP, MEM_TYPE) \ | ||
| 6442 | do { \ | ||
| 6443 | if (pdumper_object_p (po)) \ | ||
| 6444 | break; \ | ||
| 6445 | if (! (m->type == MEM_TYPE && LIVEP (m, po))) \ | ||
| 6446 | emacs_abort (); \ | ||
| 6447 | } while (0) | ||
| 6448 | |||
| 6449 | /* Check both of the above conditions, for non-symbols. */ | ||
| 6450 | #define CHECK_ALLOCATED_AND_LIVE(LIVEP, MEM_TYPE) \ | ||
| 6451 | do { \ | ||
| 6452 | CHECK_ALLOCATED (); \ | ||
| 6453 | CHECK_LIVE (LIVEP, MEM_TYPE); \ | ||
| 6454 | } while (false) | ||
| 6455 | |||
| 6456 | /* Check both of the above conditions, for symbols. */ | ||
| 6457 | #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() \ | ||
| 6458 | do { \ | ||
| 6459 | if (!c_symbol_p (ptr)) \ | ||
| 6460 | { \ | ||
| 6461 | CHECK_ALLOCATED (); \ | ||
| 6462 | CHECK_LIVE (live_symbol_p, MEM_TYPE_SYMBOL); \ | ||
| 6463 | } \ | ||
| 6464 | } while (false) | ||
| 6465 | |||
| 6466 | #else /* not GC_CHECK_MARKED_OBJECTS */ | ||
| 6467 | |||
| 6468 | #define CHECK_ALLOCATED_AND_LIVE(LIVEP, MEM_TYPE) ((void) 0) | ||
| 6469 | #define CHECK_ALLOCATED_AND_LIVE_SYMBOL() ((void) 0) | ||
| 6470 | |||
| 6471 | #endif /* not GC_CHECK_MARKED_OBJECTS */ | ||
| 6472 | |||
| 6473 | switch (XTYPE (obj)) | 6488 | switch (XTYPE (obj)) |
| 6474 | { | 6489 | { |
| 6475 | case Lisp_String: | 6490 | case Lisp_String: |
| @@ -6477,7 +6492,7 @@ process_mark_stack (ptrdiff_t base_sp) | |||
| 6477 | register struct Lisp_String *ptr = XSTRING (obj); | 6492 | register struct Lisp_String *ptr = XSTRING (obj); |
| 6478 | if (string_marked_p (ptr)) | 6493 | if (string_marked_p (ptr)) |
| 6479 | break; | 6494 | break; |
| 6480 | CHECK_ALLOCATED_AND_LIVE (live_string_p, MEM_TYPE_STRING); | 6495 | check_allocated_and_live (live_string_p, MEM_TYPE_STRING, po); |
| 6481 | set_string_marked (ptr); | 6496 | set_string_marked (ptr); |
| 6482 | mark_interval_tree (ptr->u.s.intervals); | 6497 | mark_interval_tree (ptr->u.s.intervals); |
| 6483 | #ifdef GC_CHECK_STRING_BYTES | 6498 | #ifdef GC_CHECK_STRING_BYTES |
| @@ -6498,18 +6513,7 @@ process_mark_stack (ptrdiff_t base_sp) | |||
| 6498 | enum pvec_type pvectype | 6513 | enum pvec_type pvectype |
| 6499 | = PSEUDOVECTOR_TYPE (ptr); | 6514 | = PSEUDOVECTOR_TYPE (ptr); |
| 6500 | 6515 | ||
| 6501 | #ifdef GC_CHECK_MARKED_OBJECTS | 6516 | check_allocated_and_live_vectorlike (po, obj); |
| 6502 | if (!pdumper_object_p (po) && !SUBRP (obj) && !main_thread_p (po)) | ||
| 6503 | { | ||
| 6504 | m = mem_find (po); | ||
| 6505 | if (m == MEM_NIL) | ||
| 6506 | emacs_abort (); | ||
| 6507 | if (m->type == MEM_TYPE_VECTORLIKE) | ||
| 6508 | CHECK_LIVE (live_large_vector_p, MEM_TYPE_VECTORLIKE); | ||
| 6509 | else | ||
| 6510 | CHECK_LIVE (live_small_vector_p, MEM_TYPE_VECTOR_BLOCK); | ||
| 6511 | } | ||
| 6512 | #endif | ||
| 6513 | 6517 | ||
| 6514 | switch (pvectype) | 6518 | switch (pvectype) |
| 6515 | { | 6519 | { |
| @@ -6612,7 +6616,7 @@ process_mark_stack (ptrdiff_t base_sp) | |||
| 6612 | nextsym: | 6616 | nextsym: |
| 6613 | if (symbol_marked_p (ptr)) | 6617 | if (symbol_marked_p (ptr)) |
| 6614 | break; | 6618 | break; |
| 6615 | CHECK_ALLOCATED_AND_LIVE_SYMBOL (); | 6619 | check_allocated_and_live_symbol (po, ptr); |
| 6616 | set_symbol_marked (ptr); | 6620 | set_symbol_marked (ptr); |
| 6617 | /* Attempt to catch bogus objects. */ | 6621 | /* Attempt to catch bogus objects. */ |
| 6618 | eassert (valid_lisp_object_p (ptr->u.s.function)); | 6622 | eassert (valid_lisp_object_p (ptr->u.s.function)); |
| @@ -6657,9 +6661,8 @@ process_mark_stack (ptrdiff_t base_sp) | |||
| 6657 | mark_interval_tree (string_intervals (ptr->u.s.name)); | 6661 | mark_interval_tree (string_intervals (ptr->u.s.name)); |
| 6658 | /* Inner loop to mark next symbol in this bucket, if any. */ | 6662 | /* Inner loop to mark next symbol in this bucket, if any. */ |
| 6659 | ptr = ptr->u.s.next; | 6663 | ptr = ptr->u.s.next; |
| 6660 | #if GC_CHECK_MARKED_OBJECTS | 6664 | if (GC_CHECK_MARKED_OBJECTS) |
| 6661 | po = ptr; | 6665 | po = ptr; |
| 6662 | #endif | ||
| 6663 | if (ptr) | 6666 | if (ptr) |
| 6664 | goto nextsym; | 6667 | goto nextsym; |
| 6665 | } | 6668 | } |
| @@ -6670,7 +6673,7 @@ process_mark_stack (ptrdiff_t base_sp) | |||
| 6670 | struct Lisp_Cons *ptr = XCONS (obj); | 6673 | struct Lisp_Cons *ptr = XCONS (obj); |
| 6671 | if (cons_marked_p (ptr)) | 6674 | if (cons_marked_p (ptr)) |
| 6672 | break; | 6675 | break; |
| 6673 | CHECK_ALLOCATED_AND_LIVE (live_cons_p, MEM_TYPE_CONS); | 6676 | check_allocated_and_live (live_cons_p, MEM_TYPE_CONS, po); |
| 6674 | set_cons_marked (ptr); | 6677 | set_cons_marked (ptr); |
| 6675 | /* Avoid growing the stack if the cdr is nil. | 6678 | /* Avoid growing the stack if the cdr is nil. |
| 6676 | In any case, make sure the car is expanded first. */ | 6679 | In any case, make sure the car is expanded first. */ |
| @@ -6693,7 +6696,7 @@ process_mark_stack (ptrdiff_t base_sp) | |||
| 6693 | struct Lisp_Float *f = XFLOAT (obj); | 6696 | struct Lisp_Float *f = XFLOAT (obj); |
| 6694 | if (!f) | 6697 | if (!f) |
| 6695 | break; /* for HASH_UNUSED_ENTRY_KEY */ | 6698 | break; /* for HASH_UNUSED_ENTRY_KEY */ |
| 6696 | CHECK_ALLOCATED_AND_LIVE (live_float_p, MEM_TYPE_FLOAT); | 6699 | check_allocated_and_live (live_float_p, MEM_TYPE_FLOAT, po); |
| 6697 | /* Do not mark floats stored in a dump image: these floats are | 6700 | /* Do not mark floats stored in a dump image: these floats are |
| 6698 | "cold" and do not have mark bits. */ | 6701 | "cold" and do not have mark bits. */ |
| 6699 | if (pdumper_object_p (f)) | 6702 | if (pdumper_object_p (f)) |
| @@ -6711,10 +6714,6 @@ process_mark_stack (ptrdiff_t base_sp) | |||
| 6711 | emacs_abort (); | 6714 | emacs_abort (); |
| 6712 | } | 6715 | } |
| 6713 | } | 6716 | } |
| 6714 | |||
| 6715 | #undef CHECK_LIVE | ||
| 6716 | #undef CHECK_ALLOCATED | ||
| 6717 | #undef CHECK_ALLOCATED_AND_LIVE | ||
| 6718 | } | 6717 | } |
| 6719 | 6718 | ||
| 6720 | void | 6719 | void |