aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
authorMattias EngdegÄrd2022-04-02 16:02:09 +0200
committerMattias EngdegÄrd2022-04-04 19:15:42 +0200
commit7a8798de95a57c8ff85f070075e0a0176b458578 (patch)
tree0e4d9f09daeff6ae50d3a3c6b2b9e8c2cc0646fd /src/alloc.c
parent8103b060d89ac63a12c439087bd46c30da72cd97 (diff)
downloademacs-7a8798de95a57c8ff85f070075e0a0176b458578.tar.gz
emacs-7a8798de95a57c8ff85f070075e0a0176b458578.zip
Reduce GC mark-phase recursion by using explicit stack (bug#54698)
An explict stack of objects to be traversed for marking replaces recursion for most common object types: conses, vectors, records, hash tables, symbols, functions etc. Recursion is still used for other types but those are less common and thus not as likely to cause a problem. The stack grows dynamically as required which eliminates almost all C stack overflow crashes in the GC. There is also a nontrivial GC performance improvement. * src/alloc.c (GC_REMEMBER_LAST_MARKED, GC_CDR_COUNT): New. (mark_char_table, struct mark_entry): Remove (subsumed into process_mark_stack). (struct mark_entry, struct mark_stack, mark_stk) (mark_stack_empty_p, mark_stack_pop, grow_mark_stack) (mark_stack_push_value, mark_stack_push_values) (process_mark_stack): New. (mark_object, mark_objects): Just push the object(s) and let process_mark_stack do the work.
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c618
1 files changed, 354 insertions, 264 deletions
diff --git a/src/alloc.c b/src/alloc.c
index b06dd943ba5..71f2c199b22 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6085,6 +6085,8 @@ maybe_garbage_collect (void)
6085 garbage_collect (); 6085 garbage_collect ();
6086} 6086}
6087 6087
6088static inline bool mark_stack_empty_p (void);
6089
6088/* Subroutine of Fgarbage_collect that does most of the work. */ 6090/* Subroutine of Fgarbage_collect that does most of the work. */
6089void 6091void
6090garbage_collect (void) 6092garbage_collect (void)
@@ -6100,6 +6102,8 @@ garbage_collect (void)
6100 if (garbage_collection_inhibited) 6102 if (garbage_collection_inhibited)
6101 return; 6103 return;
6102 6104
6105 eassert(mark_stack_empty_p ());
6106
6103 /* Record this function, so it appears on the profiler's backtraces. */ 6107 /* Record this function, so it appears on the profiler's backtraces. */
6104 record_in_backtrace (QAutomatic_GC, 0, 0); 6108 record_in_backtrace (QAutomatic_GC, 0, 0);
6105 6109
@@ -6222,6 +6226,8 @@ garbage_collect (void)
6222 mark_and_sweep_weak_table_contents (); 6226 mark_and_sweep_weak_table_contents ();
6223 eassert (weak_hash_tables == NULL); 6227 eassert (weak_hash_tables == NULL);
6224 6228
6229 eassert (mark_stack_empty_p ());
6230
6225 gc_sweep (); 6231 gc_sweep ();
6226 6232
6227 unmark_main_thread (); 6233 unmark_main_thread ();
@@ -6395,15 +6401,25 @@ mark_glyph_matrix (struct glyph_matrix *matrix)
6395 } 6401 }
6396} 6402}
6397 6403
6404/* Whether to remember a few of the last marked values for debugging. */
6405#define GC_REMEMBER_LAST_MARKED 0
6406
6407#if GC_REMEMBER_LAST_MARKED
6398enum { LAST_MARKED_SIZE = 1 << 9 }; /* Must be a power of 2. */ 6408enum { LAST_MARKED_SIZE = 1 << 9 }; /* Must be a power of 2. */
6399Lisp_Object last_marked[LAST_MARKED_SIZE] EXTERNALLY_VISIBLE; 6409Lisp_Object last_marked[LAST_MARKED_SIZE] EXTERNALLY_VISIBLE;
6400static int last_marked_index; 6410static int last_marked_index;
6411#endif
6401 6412
6413/* Whether to enable the mark_object_loop_halt debugging feature. */
6414#define GC_CDR_COUNT 0
6415
6416#if GC_CDR_COUNT
6402/* For debugging--call abort when we cdr down this many 6417/* For debugging--call abort when we cdr down this many
6403 links of a list, in mark_object. In debugging, 6418 links of a list, in mark_object. In debugging,
6404 the call to abort will hit a breakpoint. 6419 the call to abort will hit a breakpoint.
6405 Normally this is zero and the check never goes off. */ 6420 Normally this is zero and the check never goes off. */
6406ptrdiff_t mark_object_loop_halt EXTERNALLY_VISIBLE; 6421ptrdiff_t mark_object_loop_halt EXTERNALLY_VISIBLE;
6422#endif
6407 6423
6408static void 6424static void
6409mark_vectorlike (union vectorlike_header *header) 6425mark_vectorlike (union vectorlike_header *header)
@@ -6457,19 +6473,6 @@ mark_char_table (struct Lisp_Vector *ptr, enum pvec_type pvectype)
6457 } 6473 }
6458} 6474}
6459 6475
6460NO_INLINE /* To reduce stack depth in mark_object. */
6461static Lisp_Object
6462mark_compiled (struct Lisp_Vector *ptr)
6463{
6464 int i, size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK;
6465
6466 set_vector_marked (ptr);
6467 for (i = 0; i < size; i++)
6468 if (i != COMPILED_CONSTANTS)
6469 mark_object (ptr->contents[i]);
6470 return size > COMPILED_CONSTANTS ? ptr->contents[COMPILED_CONSTANTS] : Qnil;
6471}
6472
6473/* Mark the chain of overlays starting at PTR. */ 6476/* Mark the chain of overlays starting at PTR. */
6474 6477
6475static void 6478static void
@@ -6622,110 +6625,161 @@ mark_window (struct Lisp_Vector *ptr)
6622 (w, mark_discard_killed_buffers (w->next_buffers)); 6625 (w, mark_discard_killed_buffers (w->next_buffers));
6623} 6626}
6624 6627
6625static void 6628/* Entry of the mark stack. */
6626mark_hash_table (struct Lisp_Vector *ptr) 6629struct mark_entry
6627{ 6630{
6628 struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *) ptr; 6631 ptrdiff_t n; /* number of values, or 0 if a single value */
6629 6632 union {
6630 mark_vectorlike (&h->header); 6633 Lisp_Object value; /* when n = 0 */
6631 mark_object (h->test.name); 6634 Lisp_Object *values; /* when n > 0 */
6632 mark_object (h->test.user_hash_function); 6635 } u;
6633 mark_object (h->test.user_cmp_function); 6636};
6634 /* If hash table is not weak, mark all keys and values. For weak 6637
6635 tables, mark only the vector and not its contents --- that's what 6638/* This stack is used during marking for traversing data structures without
6636 makes it weak. */ 6639 using C recursion. */
6637 if (NILP (h->weak)) 6640struct mark_stack
6638 mark_object (h->key_and_value); 6641{
6639 else 6642 struct mark_entry *stack; /* base of stack */
6643 ptrdiff_t size; /* allocated size in entries */
6644 ptrdiff_t sp; /* current number of entries */
6645};
6646
6647static struct mark_stack mark_stk = {NULL, 0, 0};
6648
6649static inline bool
6650mark_stack_empty_p (void)
6651{
6652 return mark_stk.sp <= 0;
6653}
6654
6655/* Pop and return a value from the mark stack (which must be nonempty). */
6656static inline Lisp_Object
6657mark_stack_pop (void)
6658{
6659 eassume (!mark_stack_empty_p ());
6660 struct mark_entry *e = &mark_stk.stack[mark_stk.sp - 1];
6661 if (e->n == 0) /* single value */
6640 { 6662 {
6641 eassert (h->next_weak == NULL); 6663 --mark_stk.sp;
6642 h->next_weak = weak_hash_tables; 6664 return e->u.value;
6643 weak_hash_tables = h;
6644 set_vector_marked (XVECTOR (h->key_and_value));
6645 } 6665 }
6666 /* Array of values: pop them left to right, which seems to be slightly
6667 faster than right to left. */
6668 e->n--;
6669 if (e->n == 0)
6670 --mark_stk.sp; /* last value consumed */
6671 return (++e->u.values)[-1];
6646} 6672}
6647 6673
6648void 6674NO_INLINE static void
6649mark_objects (Lisp_Object *obj, ptrdiff_t n) 6675grow_mark_stack (void)
6650{ 6676{
6651 for (ptrdiff_t i = 0; i < n; i++) 6677 struct mark_stack *ms = &mark_stk;
6652 mark_object (obj[i]); 6678 eassert (ms->sp == ms->size);
6679 ptrdiff_t min_incr = ms->sp == 0 ? 8192 : 1;
6680 ptrdiff_t oldsize = ms->size;
6681 ms->stack = xpalloc (ms->stack, &ms->size, min_incr, -1, sizeof *ms->stack);
6682 eassert (ms->sp < ms->size);
6653} 6683}
6654 6684
6655/* Determine type of generic Lisp_Object and mark it accordingly. 6685/* Push VALUE onto the mark stack. */
6686static inline void
6687mark_stack_push_value (Lisp_Object value)
6688{
6689 if (mark_stk.sp >= mark_stk.size)
6690 grow_mark_stack ();
6691 mark_stk.stack[mark_stk.sp++] = (struct mark_entry){.n = 0, .u.value = value};
6692}
6656 6693
6657 This function implements a straightforward depth-first marking 6694/* Push the N values at VALUES onto the mark stack. */
6658 algorithm and so the recursion depth may be very high (a few 6695static inline void
6659 tens of thousands is not uncommon). To minimize stack usage, 6696mark_stack_push_values (Lisp_Object *values, ptrdiff_t n)
6660 a few cold paths are moved out to NO_INLINE functions above. 6697{
6661 In general, inlining them doesn't help you to gain more speed. */ 6698 eassume (n >= 0);
6699 if (n == 0)
6700 return;
6701 if (mark_stk.sp >= mark_stk.size)
6702 grow_mark_stack ();
6703 mark_stk.stack[mark_stk.sp++] = (struct mark_entry){.n = n,
6704 .u.values = values};
6705}
6662 6706
6663void 6707/* Traverse and mark objects on the mark stack above BASE_SP.
6664mark_object (Lisp_Object arg) 6708
6709 Traversal is depth-first using the mark stack for most common
6710 object types. Recursion is used for other types, in the hope that
6711 they are rare enough that C stack usage is kept low. */
6712static void
6713process_mark_stack (ptrdiff_t base_sp)
6665{ 6714{
6666 register Lisp_Object obj;
6667 void *po;
6668#if GC_CHECK_MARKED_OBJECTS 6715#if GC_CHECK_MARKED_OBJECTS
6669 struct mem_node *m = NULL; 6716 struct mem_node *m = NULL;
6670#endif 6717#endif
6718#if GC_CDR_COUNT
6671 ptrdiff_t cdr_count = 0; 6719 ptrdiff_t cdr_count = 0;
6720#endif
6672 6721
6673 obj = arg; 6722 eassume (mark_stk.sp >= base_sp && base_sp >= 0);
6674 loop:
6675 6723
6676 po = XPNTR (obj); 6724 while (mark_stk.sp > base_sp)
6677 if (PURE_P (po)) 6725 {
6678 return; 6726 Lisp_Object obj = mark_stack_pop ();
6727 mark_obj: ;
6728 void *po = XPNTR (obj);
6729 if (PURE_P (po))
6730 continue;
6679 6731
6680 last_marked[last_marked_index++] = obj; 6732#if GC_REMEMBER_LAST_MARKED
6681 last_marked_index &= LAST_MARKED_SIZE - 1; 6733 last_marked[last_marked_index++] = obj;
6734 last_marked_index &= LAST_MARKED_SIZE - 1;
6735#endif
6682 6736
6683 /* Perform some sanity checks on the objects marked here. Abort if 6737 /* Perform some sanity checks on the objects marked here. Abort if
6684 we encounter an object we know is bogus. This increases GC time 6738 we encounter an object we know is bogus. This increases GC time
6685 by ~80%. */ 6739 by ~80%. */
6686#if GC_CHECK_MARKED_OBJECTS 6740#if GC_CHECK_MARKED_OBJECTS
6687 6741
6688 /* Check that the object pointed to by PO is known to be a Lisp 6742 /* Check that the object pointed to by PO is known to be a Lisp
6689 structure allocated from the heap. */ 6743 structure allocated from the heap. */
6690#define CHECK_ALLOCATED() \ 6744#define CHECK_ALLOCATED() \
6691 do { \ 6745 do { \
6692 if (pdumper_object_p (po)) \ 6746 if (pdumper_object_p (po)) \
6693 { \ 6747 { \
6694 if (!pdumper_object_p_precise (po)) \ 6748 if (!pdumper_object_p_precise (po)) \
6695 emacs_abort (); \ 6749 emacs_abort (); \
6696 break; \ 6750 break; \
6697 } \ 6751 } \
6698 m = mem_find (po); \ 6752 m = mem_find (po); \
6699 if (m == MEM_NIL) \ 6753 if (m == MEM_NIL) \
6700 emacs_abort (); \ 6754 emacs_abort (); \
6701 } while (0) 6755 } while (0)
6702 6756
6703 /* Check that the object pointed to by PO is live, using predicate 6757 /* Check that the object pointed to by PO is live, using predicate
6704 function LIVEP. */ 6758 function LIVEP. */
6705#define CHECK_LIVE(LIVEP, MEM_TYPE) \ 6759#define CHECK_LIVE(LIVEP, MEM_TYPE) \
6706 do { \ 6760 do { \
6707 if (pdumper_object_p (po)) \ 6761 if (pdumper_object_p (po)) \
6708 break; \ 6762 break; \
6709 if (! (m->type == MEM_TYPE && LIVEP (m, po))) \ 6763 if (! (m->type == MEM_TYPE && LIVEP (m, po))) \
6710 emacs_abort (); \ 6764 emacs_abort (); \
6711 } while (0) 6765 } while (0)
6712 6766
6713 /* Check both of the above conditions, for non-symbols. */ 6767 /* Check both of the above conditions, for non-symbols. */
6714#define CHECK_ALLOCATED_AND_LIVE(LIVEP, MEM_TYPE) \ 6768#define CHECK_ALLOCATED_AND_LIVE(LIVEP, MEM_TYPE) \
6715 do { \ 6769 do { \
6716 CHECK_ALLOCATED (); \ 6770 CHECK_ALLOCATED (); \
6717 CHECK_LIVE (LIVEP, MEM_TYPE); \ 6771 CHECK_LIVE (LIVEP, MEM_TYPE); \
6718 } while (false) 6772 } while (false)
6719 6773
6720 /* Check both of the above conditions, for symbols. */ 6774 /* Check both of the above conditions, for symbols. */
6721#define CHECK_ALLOCATED_AND_LIVE_SYMBOL() \ 6775#define CHECK_ALLOCATED_AND_LIVE_SYMBOL() \
6722 do { \ 6776 do { \
6723 if (!c_symbol_p (ptr)) \ 6777 if (!c_symbol_p (ptr)) \
6724 { \ 6778 { \
6725 CHECK_ALLOCATED (); \ 6779 CHECK_ALLOCATED (); \
6726 CHECK_LIVE (live_symbol_p, MEM_TYPE_SYMBOL); \ 6780 CHECK_LIVE (live_symbol_p, MEM_TYPE_SYMBOL); \
6727 } \ 6781 } \
6728 } while (false) 6782 } while (false)
6729 6783
6730#else /* not GC_CHECK_MARKED_OBJECTS */ 6784#else /* not GC_CHECK_MARKED_OBJECTS */
6731 6785
@@ -6734,200 +6788,220 @@ mark_object (Lisp_Object arg)
6734 6788
6735#endif /* not GC_CHECK_MARKED_OBJECTS */ 6789#endif /* not GC_CHECK_MARKED_OBJECTS */
6736 6790
6737 switch (XTYPE (obj)) 6791 switch (XTYPE (obj))
6738 { 6792 {
6739 case Lisp_String: 6793 case Lisp_String:
6740 { 6794 {
6741 register struct Lisp_String *ptr = XSTRING (obj); 6795 register struct Lisp_String *ptr = XSTRING (obj);
6742 if (string_marked_p (ptr)) 6796 if (string_marked_p (ptr))
6743 break; 6797 break;
6744 CHECK_ALLOCATED_AND_LIVE (live_string_p, MEM_TYPE_STRING); 6798 CHECK_ALLOCATED_AND_LIVE (live_string_p, MEM_TYPE_STRING);
6745 set_string_marked (ptr); 6799 set_string_marked (ptr);
6746 mark_interval_tree (ptr->u.s.intervals); 6800 mark_interval_tree (ptr->u.s.intervals);
6747#ifdef GC_CHECK_STRING_BYTES 6801#ifdef GC_CHECK_STRING_BYTES
6748 /* Check that the string size recorded in the string is the 6802 /* Check that the string size recorded in the string is the
6749 same as the one recorded in the sdata structure. */ 6803 same as the one recorded in the sdata structure. */
6750 string_bytes (ptr); 6804 string_bytes (ptr);
6751#endif /* GC_CHECK_STRING_BYTES */ 6805#endif /* GC_CHECK_STRING_BYTES */
6752 } 6806 }
6753 break; 6807 break;
6754 6808
6755 case Lisp_Vectorlike: 6809 case Lisp_Vectorlike:
6756 { 6810 {
6757 register struct Lisp_Vector *ptr = XVECTOR (obj); 6811 register struct Lisp_Vector *ptr = XVECTOR (obj);
6758 6812
6759 if (vector_marked_p (ptr)) 6813 if (vector_marked_p (ptr))
6760 break; 6814 break;
6761 6815
6762 enum pvec_type pvectype 6816 enum pvec_type pvectype
6763 = PSEUDOVECTOR_TYPE (ptr); 6817 = PSEUDOVECTOR_TYPE (ptr);
6764 6818
6765#ifdef GC_CHECK_MARKED_OBJECTS 6819#ifdef GC_CHECK_MARKED_OBJECTS
6766 if (!pdumper_object_p (po) && !SUBRP (obj) && !main_thread_p (po)) 6820 if (!pdumper_object_p (po) && !SUBRP (obj) && !main_thread_p (po))
6767 { 6821 {
6768 m = mem_find (po); 6822 m = mem_find (po);
6769 if (m == MEM_NIL) 6823 if (m == MEM_NIL)
6770 emacs_abort (); 6824 emacs_abort ();
6771 if (m->type == MEM_TYPE_VECTORLIKE) 6825 if (m->type == MEM_TYPE_VECTORLIKE)
6772 CHECK_LIVE (live_large_vector_p, MEM_TYPE_VECTORLIKE); 6826 CHECK_LIVE (live_large_vector_p, MEM_TYPE_VECTORLIKE);
6773 else 6827 else
6774 CHECK_LIVE (live_small_vector_p, MEM_TYPE_VECTOR_BLOCK); 6828 CHECK_LIVE (live_small_vector_p, MEM_TYPE_VECTOR_BLOCK);
6775 } 6829 }
6776#endif 6830#endif
6777 6831
6778 switch (pvectype) 6832 switch (pvectype)
6779 {
6780 case PVEC_BUFFER:
6781 mark_buffer ((struct buffer *) ptr);
6782 break;
6783
6784 case PVEC_COMPILED:
6785 /* Although we could treat this just like a vector, mark_compiled
6786 returns the COMPILED_CONSTANTS element, which is marked at the
6787 next iteration of goto-loop here. This is done to avoid a few
6788 recursive calls to mark_object. */
6789 obj = mark_compiled (ptr);
6790 if (!NILP (obj))
6791 goto loop;
6792 break;
6793
6794 case PVEC_FRAME:
6795 mark_frame (ptr);
6796 break;
6797
6798 case PVEC_WINDOW:
6799 mark_window (ptr);
6800 break;
6801
6802 case PVEC_HASH_TABLE:
6803 mark_hash_table (ptr);
6804 break;
6805
6806 case PVEC_CHAR_TABLE:
6807 case PVEC_SUB_CHAR_TABLE:
6808 mark_char_table (ptr, (enum pvec_type) pvectype);
6809 break;
6810
6811 case PVEC_BOOL_VECTOR:
6812 /* bool vectors in a dump are permanently "marked", since
6813 they're in the old section and don't have mark bits.
6814 If we're looking at a dumped bool vector, we should
6815 have aborted above when we called vector_marked_p, so
6816 we should never get here. */
6817 eassert (!pdumper_object_p (ptr));
6818 set_vector_marked (ptr);
6819 break;
6820
6821 case PVEC_OVERLAY:
6822 mark_overlay (XOVERLAY (obj));
6823 break;
6824
6825 case PVEC_SUBR:
6826#ifdef HAVE_NATIVE_COMP
6827 if (SUBR_NATIVE_COMPILEDP (obj))
6828 { 6833 {
6834 case PVEC_BUFFER:
6835 mark_buffer ((struct buffer *) ptr);
6836 break;
6837
6838 case PVEC_FRAME:
6839 mark_frame (ptr);
6840 break;
6841
6842 case PVEC_WINDOW:
6843 mark_window (ptr);
6844 break;
6845
6846 case PVEC_HASH_TABLE:
6847 {
6848 struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *)ptr;
6849 ptrdiff_t size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK;
6850 set_vector_marked (ptr);
6851 mark_stack_push_values (ptr->contents, size);
6852 mark_stack_push_value (h->test.name);
6853 mark_stack_push_value (h->test.user_hash_function);
6854 mark_stack_push_value (h->test.user_cmp_function);
6855 if (NILP (h->weak))
6856 mark_stack_push_value (h->key_and_value);
6857 else
6858 {
6859 /* For weak tables, mark only the vector and not its
6860 contents --- that's what makes it weak. */
6861 eassert (h->next_weak == NULL);
6862 h->next_weak = weak_hash_tables;
6863 weak_hash_tables = h;
6864 set_vector_marked (XVECTOR (h->key_and_value));
6865 }
6866 break;
6867 }
6868
6869 case PVEC_CHAR_TABLE:
6870 case PVEC_SUB_CHAR_TABLE:
6871 mark_char_table (ptr, (enum pvec_type) pvectype);
6872 break;
6873
6874 case PVEC_BOOL_VECTOR:
6875 /* bool vectors in a dump are permanently "marked", since
6876 they're in the old section and don't have mark bits.
6877 If we're looking at a dumped bool vector, we should
6878 have aborted above when we called vector_marked_p, so
6879 we should never get here. */
6880 eassert (!pdumper_object_p (ptr));
6829 set_vector_marked (ptr); 6881 set_vector_marked (ptr);
6830 struct Lisp_Subr *subr = XSUBR (obj); 6882 break;
6831 mark_object (subr->native_intspec); 6883
6832 mark_object (subr->command_modes); 6884 case PVEC_OVERLAY:
6833 mark_object (subr->native_comp_u); 6885 mark_overlay (XOVERLAY (obj));
6834 mark_object (subr->lambda_list); 6886 break;
6835 mark_object (subr->type); 6887
6836 } 6888 case PVEC_SUBR:
6889#ifdef HAVE_NATIVE_COMP
6890 if (SUBR_NATIVE_COMPILEDP (obj))
6891 {
6892 set_vector_marked (ptr);
6893 struct Lisp_Subr *subr = XSUBR (obj);
6894 mark_stack_push_value (subr->native_intspec);
6895 mark_stack_push_value (subr->command_modes);
6896 mark_stack_push_value (subr->native_comp_u);
6897 mark_stack_push_value (subr->lambda_list);
6898 mark_stack_push_value (subr->type);
6899 }
6837#endif 6900#endif
6838 break; 6901 break;
6839 6902
6840 case PVEC_FREE: 6903 case PVEC_FREE:
6841 emacs_abort (); 6904 emacs_abort ();
6842 6905
6843 default: 6906 default:
6844 /* A regular vector, or a pseudovector needing no special 6907 {
6845 treatment. */ 6908 /* A regular vector or pseudovector needing no special
6846 mark_vectorlike (&ptr->header); 6909 treatment. */
6910 ptrdiff_t size = ptr->header.size;
6911 if (size & PSEUDOVECTOR_FLAG)
6912 size &= PSEUDOVECTOR_SIZE_MASK;
6913 set_vector_marked (ptr);
6914 mark_stack_push_values (ptr->contents, size);
6915 }
6916 break;
6917 }
6847 } 6918 }
6848 } 6919 break;
6849 break;
6850 6920
6851 case Lisp_Symbol: 6921 case Lisp_Symbol:
6852 {
6853 struct Lisp_Symbol *ptr = XBARE_SYMBOL (obj);
6854 nextsym:
6855 if (symbol_marked_p (ptr))
6856 break;
6857 CHECK_ALLOCATED_AND_LIVE_SYMBOL ();
6858 set_symbol_marked (ptr);
6859 /* Attempt to catch bogus objects. */
6860 eassert (valid_lisp_object_p (ptr->u.s.function));
6861 mark_object (ptr->u.s.function);
6862 mark_object (ptr->u.s.plist);
6863 switch (ptr->u.s.redirect)
6864 { 6922 {
6865 case SYMBOL_PLAINVAL: mark_object (SYMBOL_VAL (ptr)); break; 6923 struct Lisp_Symbol *ptr = XBARE_SYMBOL (obj);
6866 case SYMBOL_VARALIAS: 6924 nextsym:
6867 { 6925 if (symbol_marked_p (ptr))
6868 Lisp_Object tem;
6869 XSETSYMBOL (tem, SYMBOL_ALIAS (ptr));
6870 mark_object (tem);
6871 break; 6926 break;
6872 } 6927 CHECK_ALLOCATED_AND_LIVE_SYMBOL ();
6873 case SYMBOL_LOCALIZED: 6928 set_symbol_marked (ptr);
6874 mark_localized_symbol (ptr); 6929 /* Attempt to catch bogus objects. */
6875 break; 6930 eassert (valid_lisp_object_p (ptr->u.s.function));
6876 case SYMBOL_FORWARDED: 6931 mark_stack_push_value (ptr->u.s.function);
6877 /* If the value is forwarded to a buffer or keyboard field, 6932 mark_stack_push_value (ptr->u.s.plist);
6878 these are marked when we see the corresponding object. 6933 switch (ptr->u.s.redirect)
6879 And if it's forwarded to a C variable, either it's not 6934 {
6880 a Lisp_Object var, or it's staticpro'd already. */ 6935 case SYMBOL_PLAINVAL:
6881 break; 6936 mark_stack_push_value (SYMBOL_VAL (ptr));
6882 default: emacs_abort (); 6937 break;
6938 case SYMBOL_VARALIAS:
6939 {
6940 Lisp_Object tem;
6941 XSETSYMBOL (tem, SYMBOL_ALIAS (ptr));
6942 mark_stack_push_value (tem);
6943 break;
6944 }
6945 case SYMBOL_LOCALIZED:
6946 mark_localized_symbol (ptr);
6947 break;
6948 case SYMBOL_FORWARDED:
6949 /* If the value is forwarded to a buffer or keyboard field,
6950 these are marked when we see the corresponding object.
6951 And if it's forwarded to a C variable, either it's not
6952 a Lisp_Object var, or it's staticpro'd already. */
6953 break;
6954 default: emacs_abort ();
6955 }
6956 if (!PURE_P (XSTRING (ptr->u.s.name)))
6957 set_string_marked (XSTRING (ptr->u.s.name));
6958 mark_interval_tree (string_intervals (ptr->u.s.name));
6959 /* Inner loop to mark next symbol in this bucket, if any. */
6960 po = ptr = ptr->u.s.next;
6961 if (ptr)
6962 goto nextsym;
6883 } 6963 }
6884 if (!PURE_P (XSTRING (ptr->u.s.name)))
6885 set_string_marked (XSTRING (ptr->u.s.name));
6886 mark_interval_tree (string_intervals (ptr->u.s.name));
6887 /* Inner loop to mark next symbol in this bucket, if any. */
6888 po = ptr = ptr->u.s.next;
6889 if (ptr)
6890 goto nextsym;
6891 }
6892 break;
6893
6894 case Lisp_Cons:
6895 {
6896 struct Lisp_Cons *ptr = XCONS (obj);
6897 if (cons_marked_p (ptr))
6898 break; 6964 break;
6899 CHECK_ALLOCATED_AND_LIVE (live_cons_p, MEM_TYPE_CONS); 6965
6900 set_cons_marked (ptr); 6966 case Lisp_Cons:
6901 /* If the cdr is nil, avoid recursion for the car. */
6902 if (NILP (ptr->u.s.u.cdr))
6903 { 6967 {
6968 struct Lisp_Cons *ptr = XCONS (obj);
6969 if (cons_marked_p (ptr))
6970 break;
6971 CHECK_ALLOCATED_AND_LIVE (live_cons_p, MEM_TYPE_CONS);
6972 set_cons_marked (ptr);
6973 /* Avoid growing the stack if the cdr is nil.
6974 In any case, make sure the car is expanded first. */
6975 if (!NILP (ptr->u.s.u.cdr))
6976 {
6977 mark_stack_push_value (ptr->u.s.u.cdr);
6978#if GC_CDR_COUNT
6979 cdr_count++;
6980 if (cdr_count == mark_object_loop_halt)
6981 emacs_abort ();
6982#endif
6983 }
6984 /* Speedup hack for the common case (successive list elements). */
6904 obj = ptr->u.s.car; 6985 obj = ptr->u.s.car;
6905 cdr_count = 0; 6986 goto mark_obj;
6906 goto loop;
6907 } 6987 }
6908 mark_object (ptr->u.s.car);
6909 obj = ptr->u.s.u.cdr;
6910 cdr_count++;
6911 if (cdr_count == mark_object_loop_halt)
6912 emacs_abort ();
6913 goto loop;
6914 }
6915 6988
6916 case Lisp_Float: 6989 case Lisp_Float:
6917 CHECK_ALLOCATED_AND_LIVE (live_float_p, MEM_TYPE_FLOAT); 6990 CHECK_ALLOCATED_AND_LIVE (live_float_p, MEM_TYPE_FLOAT);
6918 /* Do not mark floats stored in a dump image: these floats are 6991 /* Do not mark floats stored in a dump image: these floats are
6919 "cold" and do not have mark bits. */ 6992 "cold" and do not have mark bits. */
6920 if (pdumper_object_p (XFLOAT (obj))) 6993 if (pdumper_object_p (XFLOAT (obj)))
6921 eassert (pdumper_cold_object_p (XFLOAT (obj))); 6994 eassert (pdumper_cold_object_p (XFLOAT (obj)));
6922 else if (!XFLOAT_MARKED_P (XFLOAT (obj))) 6995 else if (!XFLOAT_MARKED_P (XFLOAT (obj)))
6923 XFLOAT_MARK (XFLOAT (obj)); 6996 XFLOAT_MARK (XFLOAT (obj));
6924 break; 6997 break;
6925 6998
6926 case_Lisp_Int: 6999 case_Lisp_Int:
6927 break; 7000 break;
6928 7001
6929 default: 7002 default:
6930 emacs_abort (); 7003 emacs_abort ();
7004 }
6931 } 7005 }
6932 7006
6933#undef CHECK_LIVE 7007#undef CHECK_LIVE
@@ -6935,6 +7009,22 @@ mark_object (Lisp_Object arg)
6935#undef CHECK_ALLOCATED_AND_LIVE 7009#undef CHECK_ALLOCATED_AND_LIVE
6936} 7010}
6937 7011
7012void
7013mark_object (Lisp_Object obj)
7014{
7015 ptrdiff_t sp = mark_stk.sp;
7016 mark_stack_push_value (obj);
7017 process_mark_stack (sp);
7018}
7019
7020void
7021mark_objects (Lisp_Object *objs, ptrdiff_t n)
7022{
7023 ptrdiff_t sp = mark_stk.sp;
7024 mark_stack_push_values (objs, n);
7025 process_mark_stack (sp);
7026}
7027
6938/* Mark the Lisp pointers in the terminal objects. 7028/* Mark the Lisp pointers in the terminal objects.
6939 Called by Fgarbage_collect. */ 7029 Called by Fgarbage_collect. */
6940 7030