diff options
Diffstat (limited to 'src/alloc.c')
-rw-r--r-- | src/alloc.c | 815 |
1 files changed, 577 insertions, 238 deletions
diff --git a/src/alloc.c b/src/alloc.c index 31e8da70161..8054aa5ae59 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -44,6 +44,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "keyboard.h" #include "frame.h" #include "blockinput.h" +#include "pdumper.h" #include "termhooks.h" /* For struct terminal. */ #ifdef HAVE_WINDOW_SYSTEM #include TERM_HEADER @@ -65,16 +66,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ # include <malloc.h> #endif -#if (defined ENABLE_CHECKING \ - && defined HAVE_VALGRIND_VALGRIND_H \ - && !defined USE_VALGRIND) +#if defined HAVE_VALGRIND_VALGRIND_H && !defined USE_VALGRIND # define USE_VALGRIND 1 #endif #if USE_VALGRIND #include <valgrind/valgrind.h> #include <valgrind/memcheck.h> -static bool valgrind_p; #endif /* GC_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects. @@ -194,9 +192,6 @@ alloc_unexec_pre (void) if (!malloc_state_ptr) fatal ("malloc_get_state: %s", strerror (errno)); # endif -# ifdef HYBRID_MALLOC - bss_sbrk_did_unexec = true; -# endif } void @@ -205,22 +200,19 @@ alloc_unexec_post (void) # ifdef DOUG_LEA_MALLOC free (malloc_state_ptr); # endif -# ifdef HYBRID_MALLOC - bss_sbrk_did_unexec = false; -# endif } #endif /* Mark, unmark, query mark bit of a Lisp string. S must be a pointer to a struct Lisp_String. */ -#define MARK_STRING(S) ((S)->u.s.size |= ARRAY_MARK_FLAG) -#define UNMARK_STRING(S) ((S)->u.s.size &= ~ARRAY_MARK_FLAG) -#define STRING_MARKED_P(S) (((S)->u.s.size & ARRAY_MARK_FLAG) != 0) +#define XMARK_STRING(S) ((S)->u.s.size |= ARRAY_MARK_FLAG) +#define XUNMARK_STRING(S) ((S)->u.s.size &= ~ARRAY_MARK_FLAG) +#define XSTRING_MARKED_P(S) (((S)->u.s.size & ARRAY_MARK_FLAG) != 0) -#define VECTOR_MARK(V) ((V)->header.size |= ARRAY_MARK_FLAG) -#define VECTOR_UNMARK(V) ((V)->header.size &= ~ARRAY_MARK_FLAG) -#define VECTOR_MARKED_P(V) (((V)->header.size & ARRAY_MARK_FLAG) != 0) +#define XMARK_VECTOR(V) ((V)->header.size |= ARRAY_MARK_FLAG) +#define XUNMARK_VECTOR(V) ((V)->header.size &= ~ARRAY_MARK_FLAG) +#define XVECTOR_MARKED_P(V) (((V)->header.size & ARRAY_MARK_FLAG) != 0) /* Default value of gc_cons_threshold (see below). */ @@ -242,6 +234,12 @@ byte_ct gc_relative_threshold; byte_ct memory_full_cons_threshold; +#ifdef HAVE_PDUMPER +/* Number of finalizers run: used to loop over GC until we stop + generating garbage. */ +int number_finalizers_run; +#endif + /* True during GC. */ bool gc_in_progress; @@ -375,6 +373,27 @@ static void compact_small_strings (void); static void free_large_strings (void); extern Lisp_Object which_symbols (Lisp_Object, EMACS_INT) EXTERNALLY_VISIBLE; +/* Forward declare mark accessor functions: they're used all over the + place. */ + +inline static bool vector_marked_p (const struct Lisp_Vector *v); +inline static void set_vector_marked (struct Lisp_Vector *v); + +inline static bool vectorlike_marked_p (const union vectorlike_header *v); +inline static void set_vectorlike_marked (union vectorlike_header *v); + +inline static bool cons_marked_p (const struct Lisp_Cons *c); +inline static void set_cons_marked (struct Lisp_Cons *c); + +inline static bool string_marked_p (const struct Lisp_String *s); +inline static void set_string_marked (struct Lisp_String *s); + +inline static bool symbol_marked_p (const struct Lisp_Symbol *s); +inline static void set_symbol_marked (struct Lisp_Symbol *s); + +inline static bool interval_marked_p (INTERVAL i); +inline static void set_interval_marked (INTERVAL i); + /* When scanning the C stack for live Lisp objects, Emacs keeps track of what memory allocated via lisp_malloc and lisp_align_malloc is intended for what purpose. This enumeration specifies the type of memory. */ @@ -400,7 +419,10 @@ enum mem_type /* A unique object in pure space used to make some Lisp objects on free lists recognizable in O(1). */ -static Lisp_Object Vdead; +#ifndef ENABLE_CHECKING +static +#endif +Lisp_Object Vdead; #define DEADP(x) EQ (x, Vdead) #ifdef GC_MALLOC_CHECK @@ -478,30 +500,21 @@ static struct mem_node *mem_find (void *); #endif /* Addresses of staticpro'd variables. Initialize it to a nonzero - value; otherwise some compilers put it into BSS. */ + value if we might dump; otherwise some compilers put it into + BSS. */ -enum { NSTATICS = 2048 }; -static Lisp_Object *staticvec[NSTATICS] = {&Vpurify_flag}; +Lisp_Object *staticvec[NSTATICS] +#ifndef CANNOT_DUMP += {&Vpurify_flag} +#endif + ; /* Index of next unused slot in staticvec. */ -static int staticidx; +int staticidx; static void *pure_alloc (size_t, int); -/* True if N is a power of 2. N should be positive. */ - -#define POWER_OF_2(n) (((n) & ((n) - 1)) == 0) - -/* Return X rounded to the next multiple of Y. Y should be positive, - and Y - 1 + X should not overflow. Arguments should not have side - effects, as they are evaluated more than once. Tune for Y being a - power of 2. */ - -#define ROUNDUP(x, y) (POWER_OF_2 (y) \ - ? ((y) - 1 + (x)) & ~ ((y) - 1) \ - : ((y) - 1 + (x)) - ((y) - 1 + (x)) % (y)) - /* Return PTR rounded up to the next multiple of ALIGNMENT. */ static void * @@ -571,18 +584,18 @@ mmap_lisp_allowed_p (void) over our address space. We also can't use mmap for lisp objects if we might dump: unexec doesn't preserve the contents of mmapped regions. */ - return pointers_fit_in_lispobj_p () && !might_dump; + return pointers_fit_in_lispobj_p () && !will_dump_with_unexec_p (); } #endif /* Head of a circularly-linked list of extant finalizers. */ -static struct Lisp_Finalizer finalizers; +struct Lisp_Finalizer finalizers; /* Head of a circularly-linked list of finalizers that must be invoked because we deemed them unreachable. This list must be global, and not a local inside garbage_collect_1, in case we GC again while running finalizers. */ -static struct Lisp_Finalizer doomed_finalizers; +struct Lisp_Finalizer doomed_finalizers; /************************************************************************ @@ -931,6 +944,8 @@ xfree (void *block) { if (!block) return; + if (pdumper_object_p (block)) + return; MALLOC_BLOCK_INPUT; free (block); MALLOC_UNBLOCK_INPUT; @@ -1153,6 +1168,9 @@ lisp_malloc (size_t nbytes, enum mem_type type) static void lisp_free (void *block) { + if (pdumper_object_p (block)) + return; + MALLOC_BLOCK_INPUT; free (block); #ifndef GC_MALLOC_CHECK @@ -1569,22 +1587,23 @@ make_interval (void) /* Mark Lisp objects in interval I. */ static void -mark_interval (INTERVAL i, void *dummy) +mark_interval_tree_1 (INTERVAL i, void *dummy) { /* Intervals should never be shared. So, if extra internal checking is enabled, GC aborts if it seems to have visited an interval twice. */ - eassert (!i->gcmarkbit); - i->gcmarkbit = 1; + eassert (!interval_marked_p (i)); + set_interval_marked (i); mark_object (i->plist); } /* Mark the interval tree rooted in I. */ -#define MARK_INTERVAL_TREE(i) \ - do { \ - if (i && !i->gcmarkbit) \ - traverse_intervals_noorder (i, mark_interval, NULL); \ - } while (0) +static void +mark_interval_tree (INTERVAL i) +{ + if (i && !interval_marked_p (i)) + traverse_intervals_noorder (i, mark_interval_tree_1, NULL); +} /*********************************************************************** String Allocation @@ -1820,7 +1839,9 @@ static void init_strings (void) { empty_unibyte_string = make_pure_string ("", 0, 0, 0); + staticpro (&empty_unibyte_string); empty_multibyte_string = make_pure_string ("", 0, 0, 1); + staticpro (&empty_multibyte_string); } @@ -2114,10 +2135,10 @@ sweep_strings (void) if (s->u.s.data) { /* String was not on free-list before. */ - if (STRING_MARKED_P (s)) + if (XSTRING_MARKED_P (s)) { /* String is live; unmark it and its intervals. */ - UNMARK_STRING (s); + XUNMARK_STRING (s); /* Do not use string_(set|get)_intervals here. */ s->u.s.intervals = balance_intervals (s->u.s.intervals); @@ -2619,7 +2640,8 @@ make_formatted_string (char *buf, const char *format, ...) &= ~((bits_word) 1 << ((n) % BITS_PER_BITS_WORD))) #define FLOAT_BLOCK(fptr) \ - ((struct float_block *) (((uintptr_t) (fptr)) & ~(BLOCK_ALIGN - 1))) + (eassert (!pdumper_object_p (fptr)), \ + ((struct float_block *) (((uintptr_t) (fptr)) & ~(BLOCK_ALIGN - 1)))) #define FLOAT_INDEX(fptr) \ ((((uintptr_t) (fptr)) & (BLOCK_ALIGN - 1)) / sizeof (struct Lisp_Float)) @@ -2632,13 +2654,13 @@ struct float_block struct float_block *next; }; -#define FLOAT_MARKED_P(fptr) \ +#define XFLOAT_MARKED_P(fptr) \ GETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr))) -#define FLOAT_MARK(fptr) \ +#define XFLOAT_MARK(fptr) \ SETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr))) -#define FLOAT_UNMARK(fptr) \ +#define XFLOAT_UNMARK(fptr) \ UNSETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr))) /* Current float_block. */ @@ -2686,7 +2708,7 @@ make_float (double float_value) MALLOC_UNBLOCK_INPUT; XFLOAT_INIT (val, float_value); - eassert (!FLOAT_MARKED_P (XFLOAT (val))); + eassert (!XFLOAT_MARKED_P (XFLOAT (val))); consing_since_gc += sizeof (struct Lisp_Float); floats_consed++; total_free_floats--; @@ -2711,7 +2733,8 @@ make_float (double float_value) / (sizeof (struct Lisp_Cons) * CHAR_BIT + 1)) #define CONS_BLOCK(fptr) \ - ((struct cons_block *) ((uintptr_t) (fptr) & ~(BLOCK_ALIGN - 1))) + (eassert (!pdumper_object_p (fptr)), \ + ((struct cons_block *) ((uintptr_t) (fptr) & ~(BLOCK_ALIGN - 1)))) #define CONS_INDEX(fptr) \ (((uintptr_t) (fptr) & (BLOCK_ALIGN - 1)) / sizeof (struct Lisp_Cons)) @@ -2724,13 +2747,13 @@ struct cons_block struct cons_block *next; }; -#define CONS_MARKED_P(fptr) \ +#define XCONS_MARKED_P(fptr) \ GETMARKBIT (CONS_BLOCK (fptr), CONS_INDEX ((fptr))) -#define CONS_MARK(fptr) \ +#define XMARK_CONS(fptr) \ SETMARKBIT (CONS_BLOCK (fptr), CONS_INDEX ((fptr))) -#define CONS_UNMARK(fptr) \ +#define XUNMARK_CONS(fptr) \ UNSETMARKBIT (CONS_BLOCK (fptr), CONS_INDEX ((fptr))) /* Current cons_block. */ @@ -2803,7 +2826,7 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0, XSETCAR (val, car); XSETCDR (val, cdr); - eassert (!CONS_MARKED_P (XCONS (val))); + eassert (!XCONS_MARKED_P (XCONS (val))); consing_since_gc += sizeof (struct Lisp_Cons); total_free_conses--; cons_cells_consed++; @@ -3103,6 +3126,7 @@ static void init_vectors (void) { zero_vector = make_pure_vector (0); + staticpro (&zero_vector); } /* Allocate vector from a vector block. */ @@ -3173,17 +3197,17 @@ allocate_vector_from_block (ptrdiff_t nbytes) /* Return the memory footprint of V in bytes. */ -static ptrdiff_t -vector_nbytes (struct Lisp_Vector *v) +ptrdiff_t +vectorlike_nbytes (const union vectorlike_header *hdr) { - ptrdiff_t size = v->header.size & ~ARRAY_MARK_FLAG; + ptrdiff_t size = hdr->size & ~ARRAY_MARK_FLAG; ptrdiff_t nwords; if (size & PSEUDOVECTOR_FLAG) { - if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR)) + if (PSEUDOVECTOR_TYPEP (hdr, PVEC_BOOL_VECTOR)) { - struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) v; + struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) hdr; ptrdiff_t word_bytes = (bool_vector_words (bv->size) * sizeof (bits_word)); ptrdiff_t boolvec_bytes = bool_header_size + word_bytes; @@ -3281,9 +3305,9 @@ sweep_vectors (void) for (vector = (struct Lisp_Vector *) block->data; VECTOR_IN_BLOCK (vector, block); vector = next) { - if (VECTOR_MARKED_P (vector)) + if (XVECTOR_MARKED_P (vector)) { - VECTOR_UNMARK (vector); + XUNMARK_VECTOR (vector); total_vectors++; ptrdiff_t nbytes = vector_nbytes (vector); total_vector_slots += nbytes / word_size; @@ -3304,7 +3328,7 @@ sweep_vectors (void) total_bytes += nbytes; next = ADVANCE (next, nbytes); } - while (VECTOR_IN_BLOCK (next, block) && !VECTOR_MARKED_P (next)); + while (VECTOR_IN_BLOCK (next, block) && !vector_marked_p (next)); eassert (total_bytes % roundup_size == 0); @@ -3335,9 +3359,9 @@ sweep_vectors (void) for (lv = large_vectors; lv; lv = *lvprev) { vector = large_vector_vec (lv); - if (VECTOR_MARKED_P (vector)) + if (XVECTOR_MARKED_P (vector)) { - VECTOR_UNMARK (vector); + XUNMARK_VECTOR (vector); total_vectors++; if (vector->header.size & PSEUDOVECTOR_FLAG) total_vector_slots += vector_nbytes (vector) / word_size; @@ -3847,7 +3871,7 @@ mark_finalizer_list (struct Lisp_Finalizer *head) finalizer != head; finalizer = finalizer->next) { - VECTOR_MARK (finalizer); + set_vectorlike_marked (&finalizer->header); mark_object (finalizer->function); } } @@ -3864,7 +3888,8 @@ queue_doomed_finalizers (struct Lisp_Finalizer *dest, while (finalizer != src) { struct Lisp_Finalizer *next = finalizer->next; - if (!VECTOR_MARKED_P (finalizer) && !NILP (finalizer->function)) + if (!vectorlike_marked_p (&finalizer->header) + && !NILP (finalizer->function)) { unchain_finalizer (finalizer); finalizer_insert (dest, finalizer); @@ -3885,6 +3910,9 @@ static void run_finalizer_function (Lisp_Object function) { ptrdiff_t count = SPECPDL_INDEX (); +#ifdef HAVE_PDUMPER + ++number_finalizers_run; +#endif specbind (Qinhibit_quit, Qt); internal_condition_case_1 (call0, function, Qt, run_finalizer_handler); @@ -3929,6 +3957,126 @@ FUNCTION. FUNCTION will be run once per finalizer object. */) /************************************************************************ + Mark bit access functions + ************************************************************************/ + +/* With the rare exception of functions implementing block-based + allocation of various types, you should not directly test or set GC + mark bits on objects. Some objects might live in special memory + regions (e.g., a dump image) and might store their mark bits + elsewhere. */ + +static bool +vector_marked_p (const struct Lisp_Vector *v) +{ + if (pdumper_object_p (v)) + { + /* Look at cold_start first so that we don't have to fault in + the vector header just to tell that it's a bool vector. */ + if (pdumper_cold_object_p (v)) + { + eassert (PSEUDOVECTOR_TYPE (v) == PVEC_BOOL_VECTOR); + return true; + } + return pdumper_marked_p (v); + } + return XVECTOR_MARKED_P (v); +} + +static void +set_vector_marked (struct Lisp_Vector *v) +{ + if (pdumper_object_p (v)) + { + eassert (PSEUDOVECTOR_TYPE (v) != PVEC_BOOL_VECTOR); + pdumper_set_marked (v); + } + else + XMARK_VECTOR (v); +} + +static bool +vectorlike_marked_p (const union vectorlike_header *header) +{ + return vector_marked_p ((const struct Lisp_Vector *) header); +} + +static void +set_vectorlike_marked (union vectorlike_header *header) +{ + set_vector_marked ((struct Lisp_Vector *) header); +} + +static bool +cons_marked_p (const struct Lisp_Cons *c) +{ + return pdumper_object_p (c) + ? pdumper_marked_p (c) + : XCONS_MARKED_P (c); +} + +static void +set_cons_marked (struct Lisp_Cons *c) +{ + if (pdumper_object_p (c)) + pdumper_set_marked (c); + else + XMARK_CONS (c); +} + +static bool +string_marked_p (const struct Lisp_String *s) +{ + return pdumper_object_p (s) + ? pdumper_marked_p (s) + : XSTRING_MARKED_P (s); +} + +static void +set_string_marked (struct Lisp_String *s) +{ + if (pdumper_object_p (s)) + pdumper_set_marked (s); + else + XMARK_STRING (s); +} + +static bool +symbol_marked_p (const struct Lisp_Symbol *s) +{ + return pdumper_object_p (s) + ? pdumper_marked_p (s) + : s->u.s.gcmarkbit; +} + +static void +set_symbol_marked (struct Lisp_Symbol *s) +{ + if (pdumper_object_p (s)) + pdumper_set_marked (s); + else + s->u.s.gcmarkbit = true; +} + +static bool +interval_marked_p (INTERVAL i) +{ + return pdumper_object_p (i) + ? pdumper_marked_p (i) + : i->gcmarkbit; +} + +static void +set_interval_marked (INTERVAL i) +{ + if (pdumper_object_p (i)) + pdumper_set_marked (i); + else + i->gcmarkbit = true; +} + + +/************************************************************************ Memory Full Handling ************************************************************************/ @@ -4626,14 +4774,29 @@ static void mark_maybe_object (Lisp_Object obj) { #if USE_VALGRIND - if (valgrind_p) - VALGRIND_MAKE_MEM_DEFINED (&obj, sizeof (obj)); + VALGRIND_MAKE_MEM_DEFINED (&obj, sizeof (obj)); #endif if (FIXNUMP (obj)) return; void *po = XPNTR (obj); + + /* If the pointer is in the dumped image and the dump has a record + of the object starting at the place where the pointer points, we + definitely have an object. If the pointer is in the dumped image + and the dump has no idea what the pointer is pointing at, we + definitely _don't_ have an object. */ + if (pdumper_object_p (po)) + { + /* Don't use pdumper_object_p_precise here! It doesn't check the + tag bits. OBJ here might be complete garbage, so we need to + verify both the pointer and the tag. */ + if (XTYPE (obj) == pdumper_find_object_type (po)) + mark_object (obj); + return; + } + struct mem_node *m = mem_find (po); if (m != MEM_NIL) @@ -4703,9 +4866,8 @@ mark_maybe_pointer (void *p) { struct mem_node *m; -#if USE_VALGRIND - if (valgrind_p) - VALGRIND_MAKE_MEM_DEFINED (&p, sizeof (p)); +#ifdef USE_VALGRIND + VALGRIND_MAKE_MEM_DEFINED (&p, sizeof (p)); #endif if (sizeof (Lisp_Object) == sizeof (void *) || !HAVE_MODULES) @@ -4720,6 +4882,17 @@ mark_maybe_pointer (void *p) p = (void *) ((uintptr_t) p & ~((1 << GCTYPEBITS) - 1)); } + if (pdumper_object_p (p)) + { + enum Lisp_Type type = pdumper_find_object_type (p); + if (type != PDUMPER_NO_OBJECT) + mark_object ((type == Lisp_Symbol) + ? make_lisp_symbol(p) + : make_lisp_ptr(p, type)); + /* See mark_maybe_object for why we can confidently return. */ + return; + } + m = mem_find (p); if (m != MEM_NIL) { @@ -5076,6 +5249,12 @@ valid_pointer_p (void *p) return p ? -1 : 0; int fd[2]; + static int under_rr_state; + + if (!under_rr_state) + under_rr_state = getenv ("RUNNING_UNDER_RR") ? -1 : 1; + if (under_rr_state < 0) + return under_rr_state; /* Obviously, we cannot just access it (we would SEGV trying), so we trick the o/s to tell us whether p is a valid pointer. @@ -5115,6 +5294,9 @@ valid_lisp_object_p (Lisp_Object obj) if (p == &buffer_defaults || p == &buffer_local_symbols) return 2; + if (pdumper_object_p (p)) + return pdumper_object_p_precise (p) ? 1 : 0; + struct mem_node *m = mem_find (p); if (m == MEM_NIL) @@ -5324,7 +5506,7 @@ make_pure_c_string (const char *data, ptrdiff_t nchars) Lisp_Object string; struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String); s->u.s.size = nchars; - s->u.s.size_byte = -1; + s->u.s.size_byte = -2; s->u.s.data = (unsigned char *) data; s->u.s.intervals = NULL; XSETSTRING (string, s); @@ -5617,7 +5799,7 @@ compact_font_cache_entry (Lisp_Object entry) /* Consider OBJ if it is (font-spec . [font-entity font-entity ...]). */ if (CONSP (obj) && GC_FONT_SPEC_P (XCAR (obj)) - && !VECTOR_MARKED_P (GC_XFONT_SPEC (XCAR (obj))) + && !vectorlike_marked_p (&GC_XFONT_SPEC (XCAR (obj))->header) /* Don't use VECTORP here, as that calls ASIZE, which could hit assertion violation during GC. */ && (VECTORLIKEP (XCDR (obj)) @@ -5633,7 +5815,8 @@ compact_font_cache_entry (Lisp_Object entry) { Lisp_Object objlist; - if (VECTOR_MARKED_P (GC_XFONT_ENTITY (AREF (obj_cdr, i)))) + if (vectorlike_marked_p ( + &GC_XFONT_ENTITY (AREF (obj_cdr, i))->header)) break; objlist = AREF (AREF (obj_cdr, i), FONT_OBJLIST_INDEX); @@ -5643,7 +5826,7 @@ compact_font_cache_entry (Lisp_Object entry) struct font *font = GC_XFONT_OBJECT (val); if (!NILP (AREF (val, FONT_TYPE_INDEX)) - && VECTOR_MARKED_P(font)) + && vectorlike_marked_p(&font->header)) break; } if (CONSP (objlist)) @@ -5712,7 +5895,7 @@ compact_undo_list (Lisp_Object list) { if (CONSP (XCAR (tail)) && MARKERP (XCAR (XCAR (tail))) - && !VECTOR_MARKED_P (XMARKER (XCAR (XCAR (tail))))) + && !vectorlike_marked_p (&XMARKER (XCAR (XCAR (tail)))->header)) *prev = XCDR (tail); else prev = xcdr_addr (tail); @@ -5745,6 +5928,105 @@ mark_pinned_symbols (void) } } +static void +visit_vectorlike_root (struct gc_root_visitor visitor, + struct Lisp_Vector *ptr, + enum gc_root_type type) +{ + ptrdiff_t size = ptr->header.size; + ptrdiff_t i; + + if (size & PSEUDOVECTOR_FLAG) + size &= PSEUDOVECTOR_SIZE_MASK; + for (i = 0; i < size; i++) + visitor.visit (&ptr->contents[i], type, visitor.data); +} + +static void +visit_buffer_root (struct gc_root_visitor visitor, + struct buffer *buffer, + enum gc_root_type type) +{ + /* Buffers that are roots don't have intervals, an undo list, or + other constructs that real buffers have. */ + eassert (buffer->base_buffer == NULL); + eassert (buffer->overlays_before == NULL); + eassert (buffer->overlays_after == NULL); + + /* Visit the buffer-locals. */ + visit_vectorlike_root (visitor, (struct Lisp_Vector *) buffer, type); +} + +/* Visit GC roots stored in the Emacs data section. Used by both core + GC and by the portable dumping code. + + There are other GC roots of course, but these roots are dynamic + runtime data structures that pdump doesn't care about and so we can + continue to mark those directly in garbage_collect_1. */ +void +visit_static_gc_roots (struct gc_root_visitor visitor) +{ + visit_buffer_root (visitor, + &buffer_defaults, + GC_ROOT_BUFFER_LOCAL_DEFAULT); + visit_buffer_root (visitor, + &buffer_local_symbols, + GC_ROOT_BUFFER_LOCAL_NAME); + + for (int i = 0; i < ARRAYELTS (lispsym); i++) + { + Lisp_Object sptr = builtin_lisp_symbol (i); + visitor.visit (&sptr, GC_ROOT_C_SYMBOL, visitor.data); + } + + for (int i = 0; i < staticidx; i++) + visitor.visit (staticvec[i], GC_ROOT_STATICPRO, visitor.data); +} + +static void +mark_object_root_visitor (Lisp_Object *root_ptr, + enum gc_root_type type, + void *data) +{ + mark_object (*root_ptr); +} + +/* List of weak hash tables we found during marking the Lisp heap. + Will be NULL on entry to garbage_collect_1 and after it + returns. */ +static struct Lisp_Hash_Table *weak_hash_tables; + +NO_INLINE /* For better stack traces */ +static void +mark_and_sweep_weak_table_contents (void) +{ + struct Lisp_Hash_Table *h; + bool marked; + + /* Mark all keys and values that are in use. Keep on marking until + there is no more change. This is necessary for cases like + value-weak table A containing an entry X -> Y, where Y is used in a + key-weak table B, Z -> Y. If B comes after A in the list of weak + tables, X -> Y might be removed from A, although when looking at B + one finds that it shouldn't. */ + do + { + marked = false; + for (h = weak_hash_tables; h; h = h->next_weak) + marked |= sweep_weak_table (h, false); + } + while (marked); + + /* Remove hash table entries that aren't used. */ + while (weak_hash_tables) + { + h = weak_hash_tables; + weak_hash_tables = h->next_weak; + h->next_weak = NULL; + sweep_weak_table (h, true); + } +} + /* Subroutine of Fgarbage_collect that does most of the work. It is a separate function so that we could limit mark_stack in searching the stack frames below this function, thus avoiding the rare cases @@ -5757,13 +6039,14 @@ garbage_collect_1 (void *end) { struct buffer *nextb; char stack_top_variable; - ptrdiff_t i; bool message_p; ptrdiff_t count = SPECPDL_INDEX (); struct timespec start; Lisp_Object retval = Qnil; byte_ct tot_before = 0; + eassert (weak_hash_tables == NULL); + /* Can't GC if pure storage overflowed because we can't determine if something is a pure object or not. */ if (pure_bytes_used_before_overflow) @@ -5839,14 +6122,10 @@ garbage_collect_1 (void *end) /* Mark all the special slots that serve as the roots of accessibility. */ - mark_buffer (&buffer_defaults); - mark_buffer (&buffer_local_symbols); - - for (i = 0; i < ARRAYELTS (lispsym); i++) - mark_object (builtin_lisp_symbol (i)); - - for (i = 0; i < staticidx; i++) - mark_object (*staticvec[i]); + struct gc_root_visitor visitor; + memset (&visitor, 0, sizeof (visitor)); + visitor.visit = mark_object_root_visitor; + visit_static_gc_roots (visitor); mark_pinned_objects (); mark_pinned_symbols (); @@ -5891,11 +6170,11 @@ garbage_collect_1 (void *end) queue_doomed_finalizers (&doomed_finalizers, &finalizers); mark_finalizer_list (&doomed_finalizers); - gc_sweep (); + /* Must happen after all other marking and before gc_sweep. */ + mark_and_sweep_weak_table_contents (); + eassert (weak_hash_tables == NULL); - /* Clear the mark bits that we set in certain root slots. */ - VECTOR_UNMARK (&buffer_defaults); - VECTOR_UNMARK (&buffer_local_symbols); + gc_sweep (); unmark_main_thread (); @@ -6043,7 +6322,7 @@ mark_glyph_matrix (struct glyph_matrix *matrix) for (; glyph < end_glyph; ++glyph) if (STRINGP (glyph->object) - && !STRING_MARKED_P (XSTRING (glyph->object))) + && !string_marked_p (XSTRING (glyph->object))) mark_object (glyph->object); } } @@ -6060,13 +6339,18 @@ static int last_marked_index; ptrdiff_t mark_object_loop_halt EXTERNALLY_VISIBLE; static void -mark_vectorlike (struct Lisp_Vector *ptr) +mark_vectorlike (union vectorlike_header *header) { + struct Lisp_Vector *ptr = (struct Lisp_Vector *) header; ptrdiff_t size = ptr->header.size; ptrdiff_t i; - eassert (!VECTOR_MARKED_P (ptr)); - VECTOR_MARK (ptr); /* Else mark it. */ + eassert (!vector_marked_p (ptr)); + + /* Bool vectors have a different case in mark_object. */ + eassert (PSEUDOVECTOR_TYPE (ptr) != PVEC_BOOL_VECTOR); + + set_vector_marked (ptr); /* Else mark it. */ if (size & PSEUDOVECTOR_FLAG) size &= PSEUDOVECTOR_SIZE_MASK; @@ -6089,17 +6373,18 @@ mark_char_table (struct Lisp_Vector *ptr, enum pvec_type pvectype) /* Consult the Lisp_Sub_Char_Table layout before changing this. */ int i, idx = (pvectype == PVEC_SUB_CHAR_TABLE ? SUB_CHAR_TABLE_OFFSET : 0); - eassert (!VECTOR_MARKED_P (ptr)); - VECTOR_MARK (ptr); + eassert (!vector_marked_p (ptr)); + set_vector_marked (ptr); for (i = idx; i < size; i++) { Lisp_Object val = ptr->contents[i]; - if (FIXNUMP (val) || (SYMBOLP (val) && XSYMBOL (val)->u.s.gcmarkbit)) + if (FIXNUMP (val) || + (SYMBOLP (val) && symbol_marked_p (XSYMBOL (val)))) continue; if (SUB_CHAR_TABLE_P (val)) { - if (! VECTOR_MARKED_P (XVECTOR (val))) + if (! vector_marked_p (XVECTOR (val))) mark_char_table (XVECTOR (val), PVEC_SUB_CHAR_TABLE); } else @@ -6113,7 +6398,7 @@ mark_compiled (struct Lisp_Vector *ptr) { int i, size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK; - VECTOR_MARK (ptr); + set_vector_marked (ptr); for (i = 0; i < size; i++) if (i != COMPILED_CONSTANTS) mark_object (ptr->contents[i]); @@ -6125,12 +6410,12 @@ mark_compiled (struct Lisp_Vector *ptr) static void mark_overlay (struct Lisp_Overlay *ptr) { - for (; ptr && !VECTOR_MARKED_P (ptr); ptr = ptr->next) + for (; ptr && !vectorlike_marked_p (&ptr->header); ptr = ptr->next) { - VECTOR_MARK (ptr); + set_vectorlike_marked (&ptr->header); /* These two are always markers and can be marked fast. */ - VECTOR_MARK (XMARKER (ptr->start)); - VECTOR_MARK (XMARKER (ptr->end)); + set_vectorlike_marked (&XMARKER (ptr->start)->header); + set_vectorlike_marked (&XMARKER (ptr->end)->header); mark_object (ptr->plist); } } @@ -6141,11 +6426,11 @@ static void mark_buffer (struct buffer *buffer) { /* This is handled much like other pseudovectors... */ - mark_vectorlike ((struct Lisp_Vector *) buffer); + mark_vectorlike (&buffer->header); /* ...but there are some buffer-specific things. */ - MARK_INTERVAL_TREE (buffer_intervals (buffer)); + mark_interval_tree (buffer_intervals (buffer)); /* For now, we just don't mark the undo_list. It's done later in a special way just before the sweep phase, and after stripping @@ -6155,7 +6440,8 @@ mark_buffer (struct buffer *buffer) mark_overlay (buffer->overlays_after); /* If this is an indirect buffer, mark its base buffer. */ - if (buffer->base_buffer && !VECTOR_MARKED_P (buffer->base_buffer)) + if (buffer->base_buffer && + !vectorlike_marked_p (&buffer->base_buffer->header)) mark_buffer (buffer->base_buffer); } @@ -6174,8 +6460,8 @@ mark_face_cache (struct face_cache *c) if (face) { - if (face->font && !VECTOR_MARKED_P (face->font)) - mark_vectorlike ((struct Lisp_Vector *) face->font); + if (face->font && !vectorlike_marked_p (&face->font->header)) + mark_vectorlike (&face->font->header); for (j = 0; j < LFACE_VECTOR_SIZE; ++j) mark_object (face->lface[j]); @@ -6206,7 +6492,7 @@ mark_discard_killed_buffers (Lisp_Object list) { Lisp_Object tail, *prev = &list; - for (tail = list; CONSP (tail) && !CONS_MARKED_P (XCONS (tail)); + for (tail = list; CONSP (tail) && !cons_marked_p (XCONS (tail)); tail = XCDR (tail)) { Lisp_Object tem = XCAR (tail); @@ -6216,7 +6502,7 @@ mark_discard_killed_buffers (Lisp_Object list) *prev = XCDR (tail); else { - CONS_MARK (XCONS (tail)); + set_cons_marked (XCONS (tail)); mark_object (XCAR (tail)); prev = xcdr_addr (tail); } @@ -6225,6 +6511,72 @@ mark_discard_killed_buffers (Lisp_Object list) return list; } +static void +mark_frame (struct Lisp_Vector *ptr) +{ + struct frame *f = (struct frame *) ptr; + mark_vectorlike (&ptr->header); + mark_face_cache (f->face_cache); +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (f) && FRAME_X_OUTPUT (f)) + { + struct font *font = FRAME_FONT (f); + + if (font && !vectorlike_marked_p (&font->header)) + mark_vectorlike (&font->header); + } +#endif +} + +static void +mark_window (struct Lisp_Vector *ptr) +{ + struct window *w = (struct window *) ptr; + + mark_vectorlike (&ptr->header); + + /* Mark glyph matrices, if any. Marking window + matrices is sufficient because frame matrices + use the same glyph memory. */ + if (w->current_matrix) + { + mark_glyph_matrix (w->current_matrix); + mark_glyph_matrix (w->desired_matrix); + } + + /* Filter out killed buffers from both buffer lists + in attempt to help GC to reclaim killed buffers faster. + We can do it elsewhere for live windows, but this is the + best place to do it for dead windows. */ + wset_prev_buffers + (w, mark_discard_killed_buffers (w->prev_buffers)); + wset_next_buffers + (w, mark_discard_killed_buffers (w->next_buffers)); +} + +static void +mark_hash_table (struct Lisp_Vector *ptr) +{ + struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *) ptr; + + mark_vectorlike (&h->header); + mark_object (h->test.name); + mark_object (h->test.user_hash_function); + mark_object (h->test.user_cmp_function); + /* If hash table is not weak, mark all keys and values. For weak + tables, mark only the vector and not its contents --- that's what + makes it weak. */ + if (NILP (h->weak)) + mark_object (h->key_and_value); + else + { + eassert (h->next_weak == NULL); + h->next_weak = weak_hash_tables; + weak_hash_tables = h; + set_vector_marked (XVECTOR (h->key_and_value)); + } +} + /* Determine type of generic Lisp_Object and mark it accordingly. This function implements a straightforward depth-first marking @@ -6239,7 +6591,7 @@ mark_object (Lisp_Object arg) register Lisp_Object obj; void *po; #if GC_CHECK_MARKED_OBJECTS - struct mem_node *m; + struct mem_node *m = NULL; #endif ptrdiff_t cdr_count = 0; @@ -6262,6 +6614,12 @@ mark_object (Lisp_Object arg) structure allocated from the heap. */ #define CHECK_ALLOCATED() \ do { \ + if (pdumper_object_p(po)) \ + { \ + if (!pdumper_object_p_precise (po)) \ + emacs_abort (); \ + break; \ + } \ m = mem_find (po); \ if (m == MEM_NIL) \ emacs_abort (); \ @@ -6271,6 +6629,8 @@ mark_object (Lisp_Object arg) function LIVEP. */ #define CHECK_LIVE(LIVEP) \ do { \ + if (pdumper_object_p(po)) \ + break; \ if (!LIVEP (m, po)) \ emacs_abort (); \ } while (0) @@ -6305,11 +6665,11 @@ mark_object (Lisp_Object arg) case Lisp_String: { register struct Lisp_String *ptr = XSTRING (obj); - if (STRING_MARKED_P (ptr)) - break; + if (string_marked_p (ptr)) + break; CHECK_ALLOCATED_AND_LIVE (live_string_p); - MARK_STRING (ptr); - MARK_INTERVAL_TREE (ptr->u.s.intervals); + set_string_marked (ptr); + mark_interval_tree (ptr->u.s.intervals); #ifdef GC_CHECK_STRING_BYTES /* Check that the string size recorded in the string is the same as the one recorded in the sdata structure. */ @@ -6322,22 +6682,25 @@ mark_object (Lisp_Object arg) { register struct Lisp_Vector *ptr = XVECTOR (obj); - if (VECTOR_MARKED_P (ptr)) + if (vector_marked_p (ptr)) break; -#if GC_CHECK_MARKED_OBJECTS - m = mem_find (po); - if (m == MEM_NIL && !SUBRP (obj) && !main_thread_p (po)) - emacs_abort (); +#ifdef GC_CHECK_MARKED_OBJECTS + if (!pdumper_object_p(po)) + { + m = mem_find (po); + if (m == MEM_NIL && !SUBRP (obj) && !main_thread_p (po)) + emacs_abort (); + } #endif /* GC_CHECK_MARKED_OBJECTS */ enum pvec_type pvectype = PSEUDOVECTOR_TYPE (ptr); - if (pvectype != PVEC_SUBR - && pvectype != PVEC_BUFFER - && !main_thread_p (po)) - CHECK_LIVE (live_vector_p); + if (pvectype != PVEC_SUBR && + pvectype != PVEC_BUFFER && + !main_thread_p (po)) + CHECK_LIVE (live_vector_p); switch (pvectype) { @@ -6353,77 +6716,28 @@ mark_object (Lisp_Object arg) } #endif /* GC_CHECK_MARKED_OBJECTS */ mark_buffer ((struct buffer *) ptr); - break; - - case PVEC_COMPILED: - /* Although we could treat this just like a vector, mark_compiled - returns the COMPILED_CONSTANTS element, which is marked at the - next iteration of goto-loop here. This is done to avoid a few - recursive calls to mark_object. */ - obj = mark_compiled (ptr); - if (!NILP (obj)) - goto loop; - break; - - case PVEC_FRAME: - { - struct frame *f = (struct frame *) ptr; - - mark_vectorlike (ptr); - mark_face_cache (f->face_cache); -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (f) && FRAME_X_OUTPUT (f)) - { - struct font *font = FRAME_FONT (f); - - if (font && !VECTOR_MARKED_P (font)) - mark_vectorlike ((struct Lisp_Vector *) font); - } -#endif - } - break; - - case PVEC_WINDOW: - { - struct window *w = (struct window *) ptr; - - mark_vectorlike (ptr); - - /* Mark glyph matrices, if any. Marking window - matrices is sufficient because frame matrices - use the same glyph memory. */ - if (w->current_matrix) - { - mark_glyph_matrix (w->current_matrix); - mark_glyph_matrix (w->desired_matrix); - } - - /* Filter out killed buffers from both buffer lists - in attempt to help GC to reclaim killed buffers faster. - We can do it elsewhere for live windows, but this is the - best place to do it for dead windows. */ - wset_prev_buffers - (w, mark_discard_killed_buffers (w->prev_buffers)); - wset_next_buffers - (w, mark_discard_killed_buffers (w->next_buffers)); - } - break; + break; + + case PVEC_COMPILED: + /* Although we could treat this just like a vector, mark_compiled + returns the COMPILED_CONSTANTS element, which is marked at the + next iteration of goto-loop here. This is done to avoid a few + recursive calls to mark_object. */ + obj = mark_compiled (ptr); + if (!NILP (obj)) + goto loop; + break; + + case PVEC_FRAME: + mark_frame (ptr); + break; + + case PVEC_WINDOW: + mark_window (ptr); + break; case PVEC_HASH_TABLE: - { - struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *) ptr; - - mark_vectorlike (ptr); - mark_object (h->test.name); - mark_object (h->test.user_hash_function); - mark_object (h->test.user_cmp_function); - /* If hash table is not weak, mark all keys and values. - For weak tables, mark only the vector. */ - if (NILP (h->weak)) - mark_object (h->key_and_value); - else - VECTOR_MARK (XVECTOR (h->key_and_value)); - } + mark_hash_table (ptr); break; case PVEC_CHAR_TABLE: @@ -6431,7 +6745,17 @@ mark_object (Lisp_Object arg) mark_char_table (ptr, (enum pvec_type) pvectype); break; - case PVEC_OVERLAY: + case PVEC_BOOL_VECTOR: + /* bool vectors in a dump are permanently "marked", since + they're in the old section and don't have mark bits. + If we're looking at a dumped bool vector, we should + have aborted above when we called vector_marked_p(), so + we should never get here. */ + eassert (!pdumper_object_p (ptr)); + set_vector_marked (ptr); + break; + + case PVEC_OVERLAY: mark_overlay (XOVERLAY (obj)); break; @@ -6444,7 +6768,7 @@ mark_object (Lisp_Object arg) default: /* A regular vector, or a pseudovector needing no special treatment. */ - mark_vectorlike (ptr); + mark_vectorlike (&ptr->header); } } break; @@ -6453,10 +6777,10 @@ mark_object (Lisp_Object arg) { struct Lisp_Symbol *ptr = XSYMBOL (obj); nextsym: - if (ptr->u.s.gcmarkbit) - break; - CHECK_ALLOCATED_AND_LIVE_SYMBOL (); - ptr->u.s.gcmarkbit = 1; + if (symbol_marked_p (ptr)) + break; + CHECK_ALLOCATED_AND_LIVE_SYMBOL (); + set_symbol_marked(ptr); /* Attempt to catch bogus objects. */ eassert (valid_lisp_object_p (ptr->u.s.function)); mark_object (ptr->u.s.function); @@ -6483,8 +6807,8 @@ mark_object (Lisp_Object arg) default: emacs_abort (); } if (!PURE_P (XSTRING (ptr->u.s.name))) - MARK_STRING (XSTRING (ptr->u.s.name)); - MARK_INTERVAL_TREE (string_intervals (ptr->u.s.name)); + set_string_marked (XSTRING (ptr->u.s.name)); + mark_interval_tree (string_intervals (ptr->u.s.name)); /* Inner loop to mark next symbol in this bucket, if any. */ po = ptr = ptr->u.s.next; if (ptr) @@ -6495,10 +6819,10 @@ mark_object (Lisp_Object arg) case Lisp_Cons: { struct Lisp_Cons *ptr = XCONS (obj); - if (CONS_MARKED_P (ptr)) + if (cons_marked_p (ptr)) break; CHECK_ALLOCATED_AND_LIVE (live_cons_p); - CONS_MARK (ptr); + set_cons_marked (ptr); /* If the cdr is nil, avoid recursion for the car. */ if (NILP (ptr->u.s.u.cdr)) { @@ -6516,7 +6840,12 @@ mark_object (Lisp_Object arg) case Lisp_Float: CHECK_ALLOCATED_AND_LIVE (live_float_p); - FLOAT_MARK (XFLOAT (obj)); + /* Do not mark floats stored in a dump image: these floats are + "cold" and do not have mark bits. */ + if (pdumper_object_p (XFLOAT (obj))) + eassert (pdumper_cold_object_p (XFLOAT (obj))); + else if (!XFLOAT_MARKED_P (XFLOAT (obj))) + XFLOAT_MARK (XFLOAT (obj)); break; case_Lisp_Int: @@ -6530,6 +6859,7 @@ mark_object (Lisp_Object arg) #undef CHECK_ALLOCATED #undef CHECK_ALLOCATED_AND_LIVE } + /* Mark the Lisp pointers in the terminal objects. Called by Fgarbage_collect. */ @@ -6546,13 +6876,11 @@ mark_terminals (void) gets marked. */ mark_image_cache (t->image_cache); #endif /* HAVE_WINDOW_SYSTEM */ - if (!VECTOR_MARKED_P (t)) - mark_vectorlike ((struct Lisp_Vector *)t); + if (!vectorlike_marked_p (&t->header)) + mark_vectorlike (&t->header); } } - - /* Value is non-zero if OBJ will survive the current GC because it's either marked or does not need to be marked to survive. */ @@ -6564,27 +6892,29 @@ survives_gc_p (Lisp_Object obj) switch (XTYPE (obj)) { case_Lisp_Int: - survives_p = 1; + survives_p = true; break; case Lisp_Symbol: - survives_p = XSYMBOL (obj)->u.s.gcmarkbit; + survives_p = symbol_marked_p (XSYMBOL (obj)); break; case Lisp_String: - survives_p = STRING_MARKED_P (XSTRING (obj)); + survives_p = string_marked_p (XSTRING (obj)); break; case Lisp_Vectorlike: - survives_p = SUBRP (obj) || VECTOR_MARKED_P (XVECTOR (obj)); + survives_p = SUBRP (obj) || vector_marked_p (XVECTOR (obj)); break; case Lisp_Cons: - survives_p = CONS_MARKED_P (XCONS (obj)); + survives_p = cons_marked_p (XCONS (obj)); break; case Lisp_Float: - survives_p = FLOAT_MARKED_P (XFLOAT (obj)); + survives_p = + XFLOAT_MARKED_P (XFLOAT (obj)) || + pdumper_object_p (XFLOAT (obj)); break; default: @@ -6638,7 +6968,7 @@ sweep_conses (void) { struct Lisp_Cons *acons = ptr_bounds_copy (&cblk->conses[pos], cblk); - if (!CONS_MARKED_P (acons)) + if (!XCONS_MARKED_P (acons)) { this_free++; cblk->conses[pos].u.s.u.chain = cons_free_list; @@ -6648,7 +6978,7 @@ sweep_conses (void) else { num_used++; - CONS_UNMARK (acons); + XUNMARK_CONS (acons); } } } @@ -6691,7 +7021,7 @@ sweep_floats (void) for (int i = 0; i < lim; i++) { struct Lisp_Float *afloat = ptr_bounds_copy (&fblk->floats[i], fblk); - if (!FLOAT_MARKED_P (afloat)) + if (!XFLOAT_MARKED_P (afloat)) { this_free++; fblk->floats[i].u.chain = float_free_list; @@ -6700,7 +7030,7 @@ sweep_floats (void) else { num_used++; - FLOAT_UNMARK (afloat); + XFLOAT_UNMARK (afloat); } } lim = FLOAT_BLOCK_SIZE; @@ -6850,7 +7180,7 @@ unchain_dead_markers (struct buffer *buffer) struct Lisp_Marker *this, **prev = &BUF_MARKERS (buffer); while ((this = *prev)) - if (VECTOR_MARKED_P (this)) + if (vectorlike_marked_p (&this->header)) prev = &this->next; else { @@ -6867,14 +7197,15 @@ sweep_buffers (void) total_buffers = 0; for (buffer = all_buffers; buffer; buffer = *bprev) - if (!VECTOR_MARKED_P (buffer)) + if (!vectorlike_marked_p (&buffer->header)) { *bprev = buffer->next; lisp_free (buffer); } else { - VECTOR_UNMARK (buffer); + if (!pdumper_object_p (buffer)) + XUNMARK_VECTOR (buffer); /* Do not use buffer_(set|get)_intervals here. */ buffer->text->intervals = balance_intervals (buffer->text->intervals); unchain_dead_markers (buffer); @@ -6887,10 +7218,6 @@ sweep_buffers (void) static void gc_sweep (void) { - /* Remove or mark entries in weak hash tables. - This must be done before any object is unmarked. */ - sweep_weak_hash_tables (); - sweep_strings (); check_string_bytes (!noninteractive); sweep_conses (); @@ -6899,6 +7226,7 @@ gc_sweep (void) sweep_symbols (); sweep_buffers (); sweep_vectors (); + pdumper_clear_marks (); check_string_bytes (!noninteractive); } @@ -7151,19 +7479,34 @@ verify_alloca (void) /* Initialization. */ +static void init_alloc_once_for_pdumper (void); + void init_alloc_once (void) { + gc_cons_threshold = GC_DEFAULT_THRESHOLD; /* Even though Qt's contents are not set up, its address is known. */ Vpurify_flag = Qt; - purebeg = PUREBEG; - pure_size = PURESIZE; + PDUMPER_REMEMBER_SCALAR (buffer_defaults.header); + PDUMPER_REMEMBER_SCALAR (buffer_local_symbols.header); + + /* Call init_alloc_once_for_pdumper now so we run mem_init early. + Keep in mind that when we reload from a dump, we'll run _only_ + init_alloc_once_for_pdumper and not init_alloc_once at all. */ + pdumper_do_now_and_after_load (init_alloc_once_for_pdumper); verify_alloca (); - init_finalizer_list (&finalizers); - init_finalizer_list (&doomed_finalizers); + init_strings (); + init_vectors (); +} + +static void +init_alloc_once_for_pdumper (void) +{ + purebeg = PUREBEG; + pure_size = PURESIZE; mem_init (); Vdead = make_pure_string ("DEAD", 4, 4, 0); @@ -7172,11 +7515,11 @@ init_alloc_once (void) mallopt (M_MMAP_THRESHOLD, 64 * 1024); /* Mmap threshold. */ mallopt (M_MMAP_MAX, MMAP_MAX_AREAS); /* Max. number of mmap'ed areas. */ #endif - init_strings (); - init_vectors (); + + init_finalizer_list (&finalizers); + init_finalizer_list (&doomed_finalizers); refill_memory_reserve (); - gc_cons_threshold = GC_DEFAULT_THRESHOLD; } void @@ -7184,10 +7527,6 @@ init_alloc (void) { Vgc_elapsed = make_float (0.0); gcs_done = 0; - -#if USE_VALGRIND - valgrind_p = RUNNING_ON_VALGRIND != 0; -#endif } void |