aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Colascione2019-01-15 17:36:54 -0500
committerDaniel Colascione2019-01-15 17:37:36 -0500
commitd12e5d003d503025c1c9b0335d6518a6c3bdfae1 (patch)
tree41829446caca2d488e723843046c4f5b8931d8f8 /src
parent2a3bd6798e9670828f0402079fcc116d6d6b042d (diff)
downloademacs-d12e5d003d503025c1c9b0335d6518a6c3bdfae1.tar.gz
emacs-d12e5d003d503025c1c9b0335d6518a6c3bdfae1.zip
Add portable dumper
Add a new portable dumper as an alternative to unexec. Use it by default. * src/dmpstruct.awk: New file. * src/doc.c (get_doc_string): use will_dump_p(). * src/editfns.c (styled_format): silence compiler warning with UNINIT. * src/emacs-module.c (syms_of_module): staticpro ltv_mark. * src/emacs.c (gflags): new variable. (init_cmdargs): unwrap (string_starts_with_p, find_argument, dump_error_to_string) (load_pdump): new functions. (main): detect pdumper and --temacs invocation; actually load portable dump when detected; set gflags as appropriate; changes to init functions throughout to avoid passing explicit 'initialized' argument. * src/eval.c (inhibit_lisp_code): remove unused variable. (init_eval_once_for_pdumper): new function. (init_eval_once): call it. * src/filelock.c: CANNOT_DUMP -> will_dump_p() * src/fingerprint-dummy.c: new file * src/fingerprint.h: new file * src/fns.c: CANNOT_DUMP -> will_dump_p(), etc. (weak_hash_tables): remove (hashfn_equal, hashfn_eql): un-staticify (make_hash_table): set new 'next_weak' hash table field; drop global weak_hash_tables logic. (copy_hash_table): drop global weak_hash_tables logic. (hash_table_rehash): new function. (hash_lookup, hash_put, hash_remove_from_table, hash_clear): rehash if needed. (sweep_weak_table): un-staticify; explain logic; bool-ify. (sweep_weak_hash_tables): remove function. * src/font.c (syms_of_font): remember pdumper stuff. * src/fontset.c (syms_of_fontset): remember pdumper stuff. * src/frame.c (make_initial_frame): don't reset Vframe_list. (init_frame_once_for_pdumper, init_frame_once): new functions. (syms_of_frame): remove redundant staticpro. * src/fringe.c (init_fringe_once_for_pdumper): new functin. (init_fringe_once): call it. * src/ftcrfont.c (syms_of_ftcrfont_for_pdumper): new function. (syms_of_ftcrfont): call it. * src/ftfont.c (syms_of_ftfont_for_pdumper): new function. (syms_of_ftfont): call it. * src/ftxont.c (syms_of_ftxfont_for_pdumper): new function. (syms_of_ftxfont): call it. * src/gmalloc.c: adjust for pdumper througout (DUMPED): remove weird custom dumped indicator. * src/gnutls.c (syms_of_gnutls): pdumper note for gnutls_global_initialized. * src/image.c (syms_of_image): add pdumper comment, initializer note. * src/insdel.c (prepare_to_modify_buffer_1): account for buffer contents possibly being in dump image. * src/keyboard.c (syms_of_keyboard_for_pdumper): new function. (syms_of_keyboard): staticpro more; call pdumper syms function. * src/lisp.h: add comments throughout (gflags): declare. (will_dump_p, will_bootstrap_p, will_dump_with_pdumper_p) (dumped_with_pdumper_p, will_dump_with_unexec_p) (dumped_with_unexec_p, definitely_will_not_unexec_p): new functions. (POWER_OF_2, ROUNDUP): move macros. (PSEUDOVECTOR_TYPE, PSEUDOVECTOR_TYPEP): take vectorlike header pointer instead of vector; constify. (Lisp_Hash_Table): add comment about need to rehash on access; add comment for next_weak. (HASH_KEY, HASH_VALUE, HASH_HASH, HASH_TABLE_SIZE): const-ify. (hash_table_rehash): declare. (hash_rehash_needed_p, hash_rehash_if_needed): new functions. (finalizers, doomed_finalizers): declare extern. (SUBR_SECTION_ATTRIBUTE): new macro. (staticvec, staticidx): un-static-ify. (sweep_weak_hash_tables): remove declaration. (sweep_weak_table): declare. (hashfn_eql, hashfn_equal): declare. (number_finalizers_run): new variable. (Vdead): externify when ENABLE_CHECKING. (gc_root_type): new enumeration. (gc_root_visitor): new struct. (visit_static_gc_roots): declare. (vectorlike_nbytes): declare. (vector_nbytes): define as trivial inline function wrapper for vectorlike_nbytes. (init_obarray_once): change signature. (primary_thread): extern-ify. (init_buffer): change signature. (init_frame_once): declare. * src/lread.c (readevalloop): adjust for new dumped predicates. (init_obarray_once): new function. (ndefsubr): new variable. (defsubr): increment it. (load_path_check): adjust for pdumper. (load_path_default): use pdumper functions; adjust for dump search. * src/macfont.m (macfont_init_font_change_handler): avoid shadowing global. (syms_of_macfont_for_pdumper): new function. (syms_of_macfont): call it. * src/menu.c (syms_of_menu): staticpro more stuff. * src/minibuf.c (Ftry_completion): rehash if needed. (init_minibuf_once_for_pdumper): new function. (init_minibuf_once): call it. * src/nsfont.m (syms_of_nsfns): staticpro more. * src/nsfont.m (syms_of_nsfont_for_pdumper): new function. (syms_of_nsfont): call it. * src/nsterm.m (syms_of_nsfont): remember pdumper stuff. * src/pdumper.c: new file. * src/pdumper.h: new file. * src/process.c (init_process_emacs): use new pdumper functions instead of CANNOT_DUMP. * src/profiler.c (syms_of_profiler_for_pdumper): new function. (syms_of_profiler_for_pdumper): call it. * src/search.c (syms_of_search_for_pdumper): new function. (syms_of_search_for_pdumper): call it. * src/sheap.c (bss_sbrk_did_unexec): remove. * src/sheap.h (bss_sbrk_did_unexec): remove. * src/syntax.c (syms_of_syntax): don't redundantly staticpro re_match_object. * src/sysdep.c: use will_dump_with_unexec_p() instead of bss hack thing. * src/syssignals.h (init_sigsegv): declare. * src/systime.h (init_timefns): remove bool from signature. * src/textprop.c (syms_of_textprop): move staticpro. * src/thread.c (main_thread_p): constify. * src/thread.h (main_thread_p): constify. * src/timefns.c (init_timefns): remove bool from signature. (syms_of_timefns_for_pdumper): new function. (syms_of_timefns): call it. * src/w32.c: rearrange code. * src/w32.h (w32_relocate): declare. * src/w32fns.c (syms_of_w32fns): add pdumper note. * src/w32font.c (syms_of_w32font_for_pdumper): new function. (syms_of_w32font): call it. * src/w32heap.c (using_dynamic_heap): new variable. (init_heap): use it. * src/w32menu.c (syms_of_w32menu): add pdumper note. * src/w32proc.c (ctrl_c_handler, mainCRTStartup, _start, open_input_file) (rva_to_section, close_file_data): move here. * src/w32uniscribe.c (syms_of_w32uniscribe_for_pdumper): new function. (syms_of_w32uniscribe): call it. * src/window.c (init_window_once_for_pdumper): new function. (init_window_once): call it; staticpro more stuff. * src/xfont.c (syms_of_xfont_for_pdumper): new function. (syms_of_xfont): call it. * src/xftfont.c (syms_of_xftfont_for_pdumper): new function. (syms_of_xftfont): call it. * src/xmenu.c (syms_of_xmenu_for_pdumper): new function. (syms_of_xmenu): call it. * src/xselect.c (syms_of_xselect_for_pdumper): new function. (syms_of_xselect): call it. * src/xsettings.c (syms_of_xsettings): add more pdumper notes. * src/term.c (syms_of_xterm): add pdumper note. * src/dispnew.c (init_faces_initial): new function. (init_display_interactive): rename from init_display; use will_dump_p instead of !initialized. Initialize faces early for pdumper if needed. (init_display): new function. (syms_of_display_for_pdumper): new function. (syms_of_display): call it. * src/dbusbind.c (syms_of_dbusbind): Add TODO for bus reset on pdumper load. * src/data.c (Fdefalias): Use will_dump_p instead of Vpurify_flag. (Fmake_variable_buffer_local): silence compiler warning with -Og by making valcontents UNINIT. (arith_driver): silence compiler warning with UNINIT. * src/conf_post.h (ATTRIBUTE_SECTION): new macro. * src/composite.c (composition_gstring_put_cache): rehash hash table if needed. * src/coding.c (init_coding_once, syms_of_coding): remember pdumper stuff. * src/charset.h (charset_table_size, charset_table_user): declare. * src/charset.c (charset_table_used, charset_table_size): un-static. (init_charset_oncem, syms_of_charset): remember pdumper stuff. * src/category.c (category_table_version): remove obsolete variable. * src/callint.c (syms_of_callint): staticpro 'preserved_fns' (init_callproc): use will_dump_p instead of !CANNOT_DUMP. * src/bytecode.c (exec_byte_code): rehash table tables if needed * src/buffer.c (alloc_buffer_text, free_buffer_text): account for pdumper (init_buffer_once): add TODO; remember stuff for pdumper. (init_buffer): don't take initialized argument; adjust for pdumper. * src/atimer.c (init_atimer): initialize subr only if !initialized. * src/alloc.c: (vector_marked_p, set_vector_marked) (vectorlike_marked_p, set_vectorlike_marked, cons_marked_p) (set_cons_marked, string_marked_p, set_string_marked) (symbol_marked_p, set_symbol_marked, interval_marked_p) (set_interval_marked): new accessor routines. Use them instead of raw GC access throughout. (Vdead): make non-static when ENABLE_CHECKING. (vectorlike_nbytes): rename of 'vector_nbytes'; take a vectorlike header as input instead of a vector. (number_finalizers_run): new internal C variable. (mark_maybe_object): check for pdumper objects. (valid_pointer_p): don't be gratuitously inefficient under rr(1). (make_pure_c_string): add support for size_byte = -2 mode indicating that string data points into Emacs image rodata. (visit_vectorlike_root): visits GC roots embedded in vectorlike objects. (visit_buffer_root): visits GC roots embedded in our totally-not-a-buffer buffer global objects. (visit_static_gc_roots): visit GC roots in the Emacs data section. (mark_object_root_visitor): root callback used for conventional GC marking (weak_hash_tables): new internal variable for tracking found weak hash tables during GC. (mark_and_sweep_weak_table_contents): new weak hash table marking. (garbage_collect_1): use new GC root visitor machinery. (mark_vectorlike): accept a vectorlike_header instead of a Lisp_Vector. (mark_frame, mark_window, mark_hash_table): new functions. (mark_object): initialize 'm'; check for pdumper objects and use new mark-bit accessors throughout. Remove some object-specific marking code and move to helper functions above. (survives_gc_p): check for pdumper objects. (gc-sweep): clear pdumper mark bits. (init_alloc_once_for_pdumper): new helper function for early init called both during normal init and pdumper load. (init_alloc_once): pdumper integration. * src/Makefile.in: Rewrite dumping for pdumper; add pdumper.o; invoke temacs with --temacs command line option; build dmpstruct.h from dmpstruct.awk; stop relying on CANNOT_DUMP; clean up pdumper intermediate files during build. * nextstep/Makefile.in: build emacs.pdmp into NS packages * lisp/startup.el: account for new '--temacs' and '--dump-file' command line option. * lisp/loadup.el: rewrite early init to account for pdumper; use injected 'dump-mode' variable (set via the new '--temacs' option) instead of parsing command line. * lisp/cus-start.el: Check 'dump-mode' instead of 'purify-flag', since the new 'dump-mode' * lib-src/make-fingerprint.c: new program * lib-src/Makefile.in: built make-fingerprint utility program * configure.ac: Add --with-pdumper toggle to control pdumper support; add --with-unexec toggle to control unexec support. Add --with-dumping option to control which dumping strategy we use by default. Adjust for pdumper throughout. Check for posix_madvise. * Makefile.in: Add @DUMPING@ substitution; add pdumper mode. * .gitignore: Add make-fingerprint, temacs.in, fingerprint.c, dmpstruct.h, and pdumper dump files.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in101
-rw-r--r--src/alloc.c815
-rw-r--r--src/atimer.c3
-rw-r--r--src/buffer.c68
-rw-r--r--src/bytecode.c3
-rw-r--r--src/callint.c3
-rw-r--r--src/callproc.c4
-rw-r--r--src/category.c11
-rw-r--r--src/charset.c50
-rw-r--r--src/charset.h2
-rw-r--r--src/coding.c9
-rw-r--r--src/composite.c1
-rw-r--r--src/conf_post.h2
-rw-r--r--src/data.c8
-rw-r--r--src/dbusbind.c2
-rw-r--r--src/dispnew.c69
-rwxr-xr-xsrc/dmpstruct.awk28
-rw-r--r--src/doc.c16
-rw-r--r--src/editfns.c2
-rw-r--r--src/emacs-module.c5
-rw-r--r--src/emacs.c304
-rw-r--r--src/eval.c30
-rw-r--r--src/filelock.c11
-rw-r--r--src/fingerprint-dummy.c24
-rw-r--r--src/fingerprint.h32
-rw-r--r--src/fns.c139
-rw-r--r--src/font.c10
-rw-r--r--src/fontset.c2
-rw-r--r--src/frame.c28
-rw-r--r--src/fringe.c11
-rw-r--r--src/ftcrfont.c9
-rw-r--r--src/ftfont.c10
-rw-r--r--src/ftxfont.c9
-rw-r--r--src/gmalloc.c13
-rw-r--r--src/gnutls.c2
-rw-r--r--src/image.c3
-rw-r--r--src/insdel.c9
-rw-r--r--src/intervals.h1
-rw-r--r--src/keyboard.c41
-rw-r--r--src/lisp.h225
-rw-r--r--src/lread.c203
-rw-r--r--src/macfont.m27
-rw-r--r--src/menu.c3
-rw-r--r--src/minibuf.c30
-rw-r--r--src/nsfns.m3
-rw-r--r--src/nsfont.m11
-rw-r--r--src/nsmenu.m2
-rw-r--r--src/nsterm.m2
-rw-r--r--src/pdumper.c5593
-rw-r--r--src/pdumper.h267
-rw-r--r--src/process.c4
-rw-r--r--src/profiler.c21
-rw-r--r--src/search.c35
-rw-r--r--src/sheap.c1
-rw-r--r--src/sheap.h1
-rw-r--r--src/syntax.c3
-rw-r--r--src/sysdep.c15
-rw-r--r--src/syssignal.h3
-rw-r--r--src/systime.h2
-rw-r--r--src/textprop.c5
-rw-r--r--src/thread.c3
-rw-r--r--src/thread.h2
-rw-r--r--src/timefns.c25
-rw-r--r--src/unexw32.c116
-rw-r--r--src/w32.c34
-rw-r--r--src/w32.h2
-rw-r--r--src/w32fns.c3
-rw-r--r--src/w32font.c11
-rw-r--r--src/w32heap.c7
-rw-r--r--src/w32menu.c2
-rw-r--r--src/w32proc.c117
-rw-r--r--src/w32uniscribe.c9
-rw-r--r--src/window.c60
-rw-r--r--src/xfont.c8
-rw-r--r--src/xftfont.c9
-rw-r--r--src/xmenu.c22
-rw-r--r--src/xselect.c26
-rw-r--r--src/xsettings.c6
-rw-r--r--src/xterm.c2
79 files changed, 7952 insertions, 858 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index f409ed4db28..980bd6d10e8 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -54,8 +54,6 @@ lwlibdir = ../lwlib
54# Configuration files for .o files to depend on. 54# Configuration files for .o files to depend on.
55config_h = config.h $(srcdir)/conf_post.h 55config_h = config.h $(srcdir)/conf_post.h
56 56
57bootstrap_exe = ../src/bootstrap-emacs$(EXEEXT)
58
59## ns-app if HAVE_NS, else empty. 57## ns-app if HAVE_NS, else empty.
60OTHER_FILES = @OTHER_FILES@ 58OTHER_FILES = @OTHER_FILES@
61 59
@@ -332,7 +330,7 @@ BUILD_DETAILS = @BUILD_DETAILS@
332 330
333UNEXEC_OBJ = @UNEXEC_OBJ@ 331UNEXEC_OBJ = @UNEXEC_OBJ@
334 332
335CANNOT_DUMP=@CANNOT_DUMP@ 333DUMPING=@DUMPING@
336 334
337# 'make' verbosity. 335# 'make' verbosity.
338AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ 336AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
@@ -357,6 +355,15 @@ am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
357am__v_at_0 = @ 355am__v_at_0 = @
358am__v_at_1 = 356am__v_at_1 =
359 357
358bootstrap_exe = ../src/bootstrap-emacs$(EXEEXT)
359ifeq ($(DUMPING),pdumper)
360bootstrap_pdmp := bootstrap-emacs.pdmp # Keep in sync with loadup.el
361pdmp := emacs.pdmp
362else
363bootstrap_pdmp :=
364pdmp :=
365endif
366
360# Flags that might be in WARN_CFLAGS but are not valid for Objective C. 367# Flags that might be in WARN_CFLAGS but are not valid for Objective C.
361NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd 368NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd
362 369
@@ -395,7 +402,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
395 bignum.o buffer.o filelock.o insdel.o marker.o \ 402 bignum.o buffer.o filelock.o insdel.o marker.o \
396 minibuf.o fileio.o dired.o \ 403 minibuf.o fileio.o dired.o \
397 cmds.o casetab.o casefiddle.o indent.o search.o regex-emacs.o undo.o \ 404 cmds.o casetab.o casefiddle.o indent.o search.o regex-emacs.o undo.o \
398 alloc.o data.o doc.o editfns.o callint.o \ 405 alloc.o pdumper.o data.o doc.o editfns.o callint.o \
399 eval.o floatfns.o fns.o font.o print.o lread.o $(MODULES_OBJ) \ 406 eval.o floatfns.o fns.o font.o print.o lread.o $(MODULES_OBJ) \
400 syntax.o $(UNEXEC_OBJ) bytecode.o \ 407 syntax.o $(UNEXEC_OBJ) bytecode.o \
401 process.o gnutls.o callproc.o \ 408 process.o gnutls.o callproc.o \
@@ -446,9 +453,17 @@ FIRSTFILE_OBJ=@FIRSTFILE_OBJ@
446ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj) 453ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj)
447 454
448# Must be first, before dep inclusion! 455# Must be first, before dep inclusion!
449all: emacs$(EXEEXT) $(OTHER_FILES) 456all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES)
450.PHONY: all 457.PHONY: all
451 458
459dmpstruct_headers=$(srcdir)/lisp.h $(srcdir)/buffer.h \
460 $(srcdir)/intervals.h $(srcdir)/charset.h $(srcdir)/bignum.h
461pdumper.o: dmpstruct.h
462dmpstruct.h: $(srcdir)/dmpstruct.awk
463dmpstruct.h: $(libsrc)/make-fingerprint$(EXEEXT) $(dmpstruct_headers)
464 POSIXLY_CORRECT=1 awk -f $(srcdir)/dmpstruct.awk \
465 $(dmpstruct_headers) > $@
466
452AUTO_DEPEND = @AUTO_DEPEND@ 467AUTO_DEPEND = @AUTO_DEPEND@
453DEPDIR = deps 468DEPDIR = deps
454ifeq ($(AUTO_DEPEND),yes) 469ifeq ($(AUTO_DEPEND),yes)
@@ -511,7 +526,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
511## and emacs (which recreates bootstrap-emacs) depends on charprop, 526## and emacs (which recreates bootstrap-emacs) depends on charprop,
512## in practice this rule was always run anyway. 527## in practice this rule was always run anyway.
513$(srcdir)/macuvs.h $(lispsource)/international/charprop.el: \ 528$(srcdir)/macuvs.h $(lispsource)/international/charprop.el: \
514 bootstrap-emacs$(EXEEXT) FORCE 529 bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp) FORCE
515 $(MAKE) -C ../admin/unidata all EMACS="../$(bootstrap_exe)" 530 $(MAKE) -C ../admin/unidata all EMACS="../$(bootstrap_exe)"
516 531
517## We require charprop.el to exist before ucs-normalize.el is 532## We require charprop.el to exist before ucs-normalize.el is
@@ -542,14 +557,20 @@ ${lispintdir}/characters.elc: ${charscript:.el=.elc}
542emacs$(EXEEXT): temacs$(EXEEXT) \ 557emacs$(EXEEXT): temacs$(EXEEXT) \
543 lisp.mk $(etc)/DOC $(lisp) \ 558 lisp.mk $(etc)/DOC $(lisp) \
544 $(lispsource)/international/charprop.el ${charsets} 559 $(lispsource)/international/charprop.el ${charsets}
545ifeq ($(CANNOT_DUMP),yes) 560ifeq ($(DUMPING),unexec)
546 ln -f temacs$(EXEEXT) $@ 561 LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=dump
547else
548 LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup dump
549 ifneq ($(PAXCTL_dumped),) 562 ifneq ($(PAXCTL_dumped),)
550 $(PAXCTL_dumped) $@ 563 $(PAXCTL_dumped) emacs$(EXEEXT)
551 endif 564 endif
552 ln -f $@ bootstrap-emacs$(EXEEXT) 565 cp -f $@ bootstrap-emacs$(EXEEXT)
566else
567 cp -f temacs$(EXEEXT) emacs$(EXEEXT)
568endif
569
570ifeq ($(DUMPING),pdumper)
571$(pdmp): emacs$(EXEEXT)
572 LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump
573 cp -f $@ $(bootstrap_pdmp)
553endif 574endif
554 575
555## We run make-docfile twice because the command line may get too long 576## We run make-docfile twice because the command line may get too long
@@ -602,16 +623,30 @@ LIBEGNU_ARCHIVE = $(lib)/lib$(if $(HYBRID_MALLOC),e)gnu.a
602$(LIBEGNU_ARCHIVE): $(config_h) 623$(LIBEGNU_ARCHIVE): $(config_h)
603 $(MAKE) -C $(lib) all 624 $(MAKE) -C $(lib) all
604 625
626EMACS_DEPS_PRE=$(LIBXMENU) $(ALLOBJS)
627EMACS_DEPS_POST=$(LIBEGNU_ARCHIVE) $(EMACSRES) ${charsets} ${charscript}
628BUILD_EMACS_PRE=$(AM_V_CCLD)$(CC) $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \
629 -o $@ $(ALLOBJS)
630BUILD_EMACS_POST=$(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES)
631
632## We hash this file to generate the build fingerprint
633temacs.in$(EXEEXT): $(EMACS_DEPS_PRE) fingerprint-dummy.o $(EMACS_DEPS_POST)
634 $(BUILD_EMACS_PRE) fingerprint-dummy.o $(BUILD_EMACS_POST)
635
636$(libsrc)/make-fingerprint$(EXEEXT): $(libsrc)/make-fingerprint.c $(lib)/libgnu.a
637 $(MAKE) -C $(libsrc) make-fingerprint$(EXEEXT)
638
639fingerprint.c: temacs.in$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT)
640 $(libsrc)/make-fingerprint$(EXEEXT) temacs.in$(EXEEXT) > fingerprint.c
641
605## We have to create $(etc) here because init_cmdargs tests its 642## We have to create $(etc) here because init_cmdargs tests its
606## existence when setting Vinstallation_directory (FIXME?). 643## existence when setting Vinstallation_directory (FIXME?).
607## This goes on to affect various things, and the emacs binary fails 644## This goes on to affect various things, and the emacs binary fails
608## to start if Vinstallation_directory has the wrong value. 645## to start if Vinstallation_directory has the wrong value.
609temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) \ 646temacs$(EXEEXT): $(EMACS_DEPS_PRE) fingerprint.o $(EMACS_DEPS_POST)
610 $(LIBEGNU_ARCHIVE) $(EMACSRES) ${charsets} ${charscript} 647 $(BUILD_EMACS_PRE) fingerprint.o $(BUILD_EMACS_POST)
611 $(AM_V_CCLD)$(CC) $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \
612 -o temacs $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES)
613 $(MKDIR_P) $(etc) 648 $(MKDIR_P) $(etc)
614ifneq ($(CANNOT_DUMP),yes) 649ifeq ($(DUMPING),unexec)
615 ifneq ($(PAXCTL_notdumped),) 650 ifneq ($(PAXCTL_notdumped),)
616 $(PAXCTL_notdumped) $@ 651 $(PAXCTL_notdumped) $@
617 endif 652 endif
@@ -638,7 +673,7 @@ emacs.res: FORCE
638 $(MAKE) -C ../nt ../src/emacs.res 673 $(MAKE) -C ../nt ../src/emacs.res
639 674
640.PHONY: ns-app 675.PHONY: ns-app
641ns-app: emacs$(EXEEXT) 676ns-app: emacs$(EXEEXT) $(pdmp)
642 $(MAKE) -C ../nextstep all 677 $(MAKE) -C ../nextstep all
643 678
644.PHONY: mostlyclean clean bootstrap-clean distclean maintainer-clean 679.PHONY: mostlyclean clean bootstrap-clean distclean maintainer-clean
@@ -646,8 +681,11 @@ ns-app: emacs$(EXEEXT)
646 681
647mostlyclean: 682mostlyclean:
648 rm -f temacs$(EXEEXT) core ./*.core \#* ./*.o 683 rm -f temacs$(EXEEXT) core ./*.core \#* ./*.o
684 rm -f temacs.in$(EXEEXT) fingerprint.c dmpstruct.h
685 rm -f emacs.pdmp
649 rm -f ../etc/DOC 686 rm -f ../etc/DOC
650 rm -f bootstrap-emacs$(EXEEXT) emacs-$(version)$(EXEEXT) 687 rm -f bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp)
688 rm -f emacs-$(version)$(EXEEXT)
651 rm -f buildobj.h 689 rm -f buildobj.h
652 rm -f globals.h gl-stamp 690 rm -f globals.h gl-stamp
653 rm -f ./*.res ./*.tmp 691 rm -f ./*.res ./*.tmp
@@ -732,7 +770,7 @@ tags: TAGS ../lisp/TAGS $(lwlibdir)/TAGS
732## but now that we require GNU make, we can simply specify 770## but now that we require GNU make, we can simply specify
733## bootstrap-emacs$(EXEEXT) as an order-only prerequisite. 771## bootstrap-emacs$(EXEEXT) as an order-only prerequisite.
734 772
735%.elc: %.el | bootstrap-emacs$(EXEEXT) 773%.elc: %.el | bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp)
736 @$(MAKE) -C ../lisp EMACS="$(bootstrap_exe)" THEFILE=$< $<c 774 @$(MAKE) -C ../lisp EMACS="$(bootstrap_exe)" THEFILE=$< $<c
737 775
738## VCSWITNESS points to the file that holds info about the current checkout. 776## VCSWITNESS points to the file that holds info about the current checkout.
@@ -740,24 +778,35 @@ tags: TAGS ../lisp/TAGS $(lwlibdir)/TAGS
740## If empty it is ignored; the parent makefile can set it to some other value. 778## If empty it is ignored; the parent makefile can set it to some other value.
741VCSWITNESS = 779VCSWITNESS =
742 780
743$(lispsource)/loaddefs.el: $(VCSWITNESS) | bootstrap-emacs$(EXEEXT) 781$(lispsource)/loaddefs.el: $(VCSWITNESS) | \
782 bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp)
744 $(MAKE) -C ../lisp autoloads EMACS="$(bootstrap_exe)" 783 $(MAKE) -C ../lisp autoloads EMACS="$(bootstrap_exe)"
745 784
746## Dump an Emacs executable named bootstrap-emacs containing the 785## Dump an Emacs executable named bootstrap-emacs containing the
747## files from loadup.el in source form. 786## files from loadup.el in source form.
787
748bootstrap-emacs$(EXEEXT): temacs$(EXEEXT) 788bootstrap-emacs$(EXEEXT): temacs$(EXEEXT)
749 $(MAKE) -C ../lisp update-subdirs 789 $(MAKE) -C ../lisp update-subdirs
750ifeq ($(CANNOT_DUMP),yes) 790ifeq ($(DUMPING),unexec)
751 ln -f temacs$(EXEEXT) $@ 791 $(RUN_TEMACS) --batch $(BUILD_DETAILS) -l loadup --temacs=bootstrap
752else
753 $(RUN_TEMACS) --batch $(BUILD_DETAILS) --load loadup bootstrap
754 ifneq ($(PAXCTL_dumped),) 792 ifneq ($(PAXCTL_dumped),)
755 $(PAXCTL_dumped) emacs$(EXEEXT) 793 $(PAXCTL_dumped) emacs$(EXEEXT)
756 endif 794 endif
757 mv -f emacs$(EXEEXT) $@ 795 mv -f emacs$(EXEEXT) bootstrap-emacs$(EXEEXT)
796 @: Compile some files earlier to speed up further compilation.
797 $(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)"
798else
799 @: In the pdumper case, make compile-first after the dump
800 cp -f temacs$(EXEEXT) bootstrap-emacs$(EXEEXT)
758endif 801endif
802
803ifeq ($(DUMPING),pdumper)
804$(bootstrap_pdmp): bootstrap-emacs$(EXEEXT)
805 rm -f $@
806 $(RUN_TEMACS) --batch $(BUILD_DETAILS) -l loadup --temacs=pbootstrap
759 @: Compile some files earlier to speed up further compilation. 807 @: Compile some files earlier to speed up further compilation.
760 $(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)" 808 $(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)"
809endif
761 810
762### Flymake support (for C only) 811### Flymake support (for C only)
763check-syntax: 812check-syntax:
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/>. */
44#include "keyboard.h" 44#include "keyboard.h"
45#include "frame.h" 45#include "frame.h"
46#include "blockinput.h" 46#include "blockinput.h"
47#include "pdumper.h"
47#include "termhooks.h" /* For struct terminal. */ 48#include "termhooks.h" /* For struct terminal. */
48#ifdef HAVE_WINDOW_SYSTEM 49#ifdef HAVE_WINDOW_SYSTEM
49#include TERM_HEADER 50#include TERM_HEADER
@@ -65,16 +66,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
65# include <malloc.h> 66# include <malloc.h>
66#endif 67#endif
67 68
68#if (defined ENABLE_CHECKING \ 69#if defined HAVE_VALGRIND_VALGRIND_H && !defined USE_VALGRIND
69 && defined HAVE_VALGRIND_VALGRIND_H \
70 && !defined USE_VALGRIND)
71# define USE_VALGRIND 1 70# define USE_VALGRIND 1
72#endif 71#endif
73 72
74#if USE_VALGRIND 73#if USE_VALGRIND
75#include <valgrind/valgrind.h> 74#include <valgrind/valgrind.h>
76#include <valgrind/memcheck.h> 75#include <valgrind/memcheck.h>
77static bool valgrind_p;
78#endif 76#endif
79 77
80/* GC_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects. 78/* GC_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects.
@@ -194,9 +192,6 @@ alloc_unexec_pre (void)
194 if (!malloc_state_ptr) 192 if (!malloc_state_ptr)
195 fatal ("malloc_get_state: %s", strerror (errno)); 193 fatal ("malloc_get_state: %s", strerror (errno));
196# endif 194# endif
197# ifdef HYBRID_MALLOC
198 bss_sbrk_did_unexec = true;
199# endif
200} 195}
201 196
202void 197void
@@ -205,22 +200,19 @@ alloc_unexec_post (void)
205# ifdef DOUG_LEA_MALLOC 200# ifdef DOUG_LEA_MALLOC
206 free (malloc_state_ptr); 201 free (malloc_state_ptr);
207# endif 202# endif
208# ifdef HYBRID_MALLOC
209 bss_sbrk_did_unexec = false;
210# endif
211} 203}
212#endif 204#endif
213 205
214/* Mark, unmark, query mark bit of a Lisp string. S must be a pointer 206/* Mark, unmark, query mark bit of a Lisp string. S must be a pointer
215 to a struct Lisp_String. */ 207 to a struct Lisp_String. */
216 208
217#define MARK_STRING(S) ((S)->u.s.size |= ARRAY_MARK_FLAG) 209#define XMARK_STRING(S) ((S)->u.s.size |= ARRAY_MARK_FLAG)
218#define UNMARK_STRING(S) ((S)->u.s.size &= ~ARRAY_MARK_FLAG) 210#define XUNMARK_STRING(S) ((S)->u.s.size &= ~ARRAY_MARK_FLAG)
219#define STRING_MARKED_P(S) (((S)->u.s.size & ARRAY_MARK_FLAG) != 0) 211#define XSTRING_MARKED_P(S) (((S)->u.s.size & ARRAY_MARK_FLAG) != 0)
220 212
221#define VECTOR_MARK(V) ((V)->header.size |= ARRAY_MARK_FLAG) 213#define XMARK_VECTOR(V) ((V)->header.size |= ARRAY_MARK_FLAG)
222#define VECTOR_UNMARK(V) ((V)->header.size &= ~ARRAY_MARK_FLAG) 214#define XUNMARK_VECTOR(V) ((V)->header.size &= ~ARRAY_MARK_FLAG)
223#define VECTOR_MARKED_P(V) (((V)->header.size & ARRAY_MARK_FLAG) != 0) 215#define XVECTOR_MARKED_P(V) (((V)->header.size & ARRAY_MARK_FLAG) != 0)
224 216
225/* Default value of gc_cons_threshold (see below). */ 217/* Default value of gc_cons_threshold (see below). */
226 218
@@ -242,6 +234,12 @@ byte_ct gc_relative_threshold;
242 234
243byte_ct memory_full_cons_threshold; 235byte_ct memory_full_cons_threshold;
244 236
237#ifdef HAVE_PDUMPER
238/* Number of finalizers run: used to loop over GC until we stop
239 generating garbage. */
240int number_finalizers_run;
241#endif
242
245/* True during GC. */ 243/* True during GC. */
246 244
247bool gc_in_progress; 245bool gc_in_progress;
@@ -375,6 +373,27 @@ static void compact_small_strings (void);
375static void free_large_strings (void); 373static void free_large_strings (void);
376extern Lisp_Object which_symbols (Lisp_Object, EMACS_INT) EXTERNALLY_VISIBLE; 374extern Lisp_Object which_symbols (Lisp_Object, EMACS_INT) EXTERNALLY_VISIBLE;
377 375
376/* Forward declare mark accessor functions: they're used all over the
377 place. */
378
379inline static bool vector_marked_p (const struct Lisp_Vector *v);
380inline static void set_vector_marked (struct Lisp_Vector *v);
381
382inline static bool vectorlike_marked_p (const union vectorlike_header *v);
383inline static void set_vectorlike_marked (union vectorlike_header *v);
384
385inline static bool cons_marked_p (const struct Lisp_Cons *c);
386inline static void set_cons_marked (struct Lisp_Cons *c);
387
388inline static bool string_marked_p (const struct Lisp_String *s);
389inline static void set_string_marked (struct Lisp_String *s);
390
391inline static bool symbol_marked_p (const struct Lisp_Symbol *s);
392inline static void set_symbol_marked (struct Lisp_Symbol *s);
393
394inline static bool interval_marked_p (INTERVAL i);
395inline static void set_interval_marked (INTERVAL i);
396
378/* When scanning the C stack for live Lisp objects, Emacs keeps track of 397/* When scanning the C stack for live Lisp objects, Emacs keeps track of
379 what memory allocated via lisp_malloc and lisp_align_malloc is intended 398 what memory allocated via lisp_malloc and lisp_align_malloc is intended
380 for what purpose. This enumeration specifies the type of memory. */ 399 for what purpose. This enumeration specifies the type of memory. */
@@ -400,7 +419,10 @@ enum mem_type
400/* A unique object in pure space used to make some Lisp objects 419/* A unique object in pure space used to make some Lisp objects
401 on free lists recognizable in O(1). */ 420 on free lists recognizable in O(1). */
402 421
403static Lisp_Object Vdead; 422#ifndef ENABLE_CHECKING
423static
424#endif
425Lisp_Object Vdead;
404#define DEADP(x) EQ (x, Vdead) 426#define DEADP(x) EQ (x, Vdead)
405 427
406#ifdef GC_MALLOC_CHECK 428#ifdef GC_MALLOC_CHECK
@@ -478,30 +500,21 @@ static struct mem_node *mem_find (void *);
478#endif 500#endif
479 501
480/* Addresses of staticpro'd variables. Initialize it to a nonzero 502/* Addresses of staticpro'd variables. Initialize it to a nonzero
481 value; otherwise some compilers put it into BSS. */ 503 value if we might dump; otherwise some compilers put it into
504 BSS. */
482 505
483enum { NSTATICS = 2048 }; 506Lisp_Object *staticvec[NSTATICS]
484static Lisp_Object *staticvec[NSTATICS] = {&Vpurify_flag}; 507#ifndef CANNOT_DUMP
508= {&Vpurify_flag}
509#endif
510 ;
485 511
486/* Index of next unused slot in staticvec. */ 512/* Index of next unused slot in staticvec. */
487 513
488static int staticidx; 514int staticidx;
489 515
490static void *pure_alloc (size_t, int); 516static void *pure_alloc (size_t, int);
491 517
492/* True if N is a power of 2. N should be positive. */
493
494#define POWER_OF_2(n) (((n) & ((n) - 1)) == 0)
495
496/* Return X rounded to the next multiple of Y. Y should be positive,
497 and Y - 1 + X should not overflow. Arguments should not have side
498 effects, as they are evaluated more than once. Tune for Y being a
499 power of 2. */
500
501#define ROUNDUP(x, y) (POWER_OF_2 (y) \
502 ? ((y) - 1 + (x)) & ~ ((y) - 1) \
503 : ((y) - 1 + (x)) - ((y) - 1 + (x)) % (y))
504
505/* Return PTR rounded up to the next multiple of ALIGNMENT. */ 518/* Return PTR rounded up to the next multiple of ALIGNMENT. */
506 519
507static void * 520static void *
@@ -571,18 +584,18 @@ mmap_lisp_allowed_p (void)
571 over our address space. We also can't use mmap for lisp objects 584 over our address space. We also can't use mmap for lisp objects
572 if we might dump: unexec doesn't preserve the contents of mmapped 585 if we might dump: unexec doesn't preserve the contents of mmapped
573 regions. */ 586 regions. */
574 return pointers_fit_in_lispobj_p () && !might_dump; 587 return pointers_fit_in_lispobj_p () && !will_dump_with_unexec_p ();
575} 588}
576#endif 589#endif
577 590
578/* Head of a circularly-linked list of extant finalizers. */ 591/* Head of a circularly-linked list of extant finalizers. */
579static struct Lisp_Finalizer finalizers; 592struct Lisp_Finalizer finalizers;
580 593
581/* Head of a circularly-linked list of finalizers that must be invoked 594/* Head of a circularly-linked list of finalizers that must be invoked
582 because we deemed them unreachable. This list must be global, and 595 because we deemed them unreachable. This list must be global, and
583 not a local inside garbage_collect_1, in case we GC again while 596 not a local inside garbage_collect_1, in case we GC again while
584 running finalizers. */ 597 running finalizers. */
585static struct Lisp_Finalizer doomed_finalizers; 598struct Lisp_Finalizer doomed_finalizers;
586 599
587 600
588/************************************************************************ 601/************************************************************************
@@ -931,6 +944,8 @@ xfree (void *block)
931{ 944{
932 if (!block) 945 if (!block)
933 return; 946 return;
947 if (pdumper_object_p (block))
948 return;
934 MALLOC_BLOCK_INPUT; 949 MALLOC_BLOCK_INPUT;
935 free (block); 950 free (block);
936 MALLOC_UNBLOCK_INPUT; 951 MALLOC_UNBLOCK_INPUT;
@@ -1153,6 +1168,9 @@ lisp_malloc (size_t nbytes, enum mem_type type)
1153static void 1168static void
1154lisp_free (void *block) 1169lisp_free (void *block)
1155{ 1170{
1171 if (pdumper_object_p (block))
1172 return;
1173
1156 MALLOC_BLOCK_INPUT; 1174 MALLOC_BLOCK_INPUT;
1157 free (block); 1175 free (block);
1158#ifndef GC_MALLOC_CHECK 1176#ifndef GC_MALLOC_CHECK
@@ -1569,22 +1587,23 @@ make_interval (void)
1569/* Mark Lisp objects in interval I. */ 1587/* Mark Lisp objects in interval I. */
1570 1588
1571static void 1589static void
1572mark_interval (INTERVAL i, void *dummy) 1590mark_interval_tree_1 (INTERVAL i, void *dummy)
1573{ 1591{
1574 /* Intervals should never be shared. So, if extra internal checking is 1592 /* Intervals should never be shared. So, if extra internal checking is
1575 enabled, GC aborts if it seems to have visited an interval twice. */ 1593 enabled, GC aborts if it seems to have visited an interval twice. */
1576 eassert (!i->gcmarkbit); 1594 eassert (!interval_marked_p (i));
1577 i->gcmarkbit = 1; 1595 set_interval_marked (i);
1578 mark_object (i->plist); 1596 mark_object (i->plist);
1579} 1597}
1580 1598
1581/* Mark the interval tree rooted in I. */ 1599/* Mark the interval tree rooted in I. */
1582 1600
1583#define MARK_INTERVAL_TREE(i) \ 1601static void
1584 do { \ 1602mark_interval_tree (INTERVAL i)
1585 if (i && !i->gcmarkbit) \ 1603{
1586 traverse_intervals_noorder (i, mark_interval, NULL); \ 1604 if (i && !interval_marked_p (i))
1587 } while (0) 1605 traverse_intervals_noorder (i, mark_interval_tree_1, NULL);
1606}
1588 1607
1589/*********************************************************************** 1608/***********************************************************************
1590 String Allocation 1609 String Allocation
@@ -1820,7 +1839,9 @@ static void
1820init_strings (void) 1839init_strings (void)
1821{ 1840{
1822 empty_unibyte_string = make_pure_string ("", 0, 0, 0); 1841 empty_unibyte_string = make_pure_string ("", 0, 0, 0);
1842 staticpro (&empty_unibyte_string);
1823 empty_multibyte_string = make_pure_string ("", 0, 0, 1); 1843 empty_multibyte_string = make_pure_string ("", 0, 0, 1);
1844 staticpro (&empty_multibyte_string);
1824} 1845}
1825 1846
1826 1847
@@ -2114,10 +2135,10 @@ sweep_strings (void)
2114 if (s->u.s.data) 2135 if (s->u.s.data)
2115 { 2136 {
2116 /* String was not on free-list before. */ 2137 /* String was not on free-list before. */
2117 if (STRING_MARKED_P (s)) 2138 if (XSTRING_MARKED_P (s))
2118 { 2139 {
2119 /* String is live; unmark it and its intervals. */ 2140 /* String is live; unmark it and its intervals. */
2120 UNMARK_STRING (s); 2141 XUNMARK_STRING (s);
2121 2142
2122 /* Do not use string_(set|get)_intervals here. */ 2143 /* Do not use string_(set|get)_intervals here. */
2123 s->u.s.intervals = balance_intervals (s->u.s.intervals); 2144 s->u.s.intervals = balance_intervals (s->u.s.intervals);
@@ -2619,7 +2640,8 @@ make_formatted_string (char *buf, const char *format, ...)
2619 &= ~((bits_word) 1 << ((n) % BITS_PER_BITS_WORD))) 2640 &= ~((bits_word) 1 << ((n) % BITS_PER_BITS_WORD)))
2620 2641
2621#define FLOAT_BLOCK(fptr) \ 2642#define FLOAT_BLOCK(fptr) \
2622 ((struct float_block *) (((uintptr_t) (fptr)) & ~(BLOCK_ALIGN - 1))) 2643 (eassert (!pdumper_object_p (fptr)), \
2644 ((struct float_block *) (((uintptr_t) (fptr)) & ~(BLOCK_ALIGN - 1))))
2623 2645
2624#define FLOAT_INDEX(fptr) \ 2646#define FLOAT_INDEX(fptr) \
2625 ((((uintptr_t) (fptr)) & (BLOCK_ALIGN - 1)) / sizeof (struct Lisp_Float)) 2647 ((((uintptr_t) (fptr)) & (BLOCK_ALIGN - 1)) / sizeof (struct Lisp_Float))
@@ -2632,13 +2654,13 @@ struct float_block
2632 struct float_block *next; 2654 struct float_block *next;
2633}; 2655};
2634 2656
2635#define FLOAT_MARKED_P(fptr) \ 2657#define XFLOAT_MARKED_P(fptr) \
2636 GETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr))) 2658 GETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr)))
2637 2659
2638#define FLOAT_MARK(fptr) \ 2660#define XFLOAT_MARK(fptr) \
2639 SETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr))) 2661 SETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr)))
2640 2662
2641#define FLOAT_UNMARK(fptr) \ 2663#define XFLOAT_UNMARK(fptr) \
2642 UNSETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr))) 2664 UNSETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr)))
2643 2665
2644/* Current float_block. */ 2666/* Current float_block. */
@@ -2686,7 +2708,7 @@ make_float (double float_value)
2686 MALLOC_UNBLOCK_INPUT; 2708 MALLOC_UNBLOCK_INPUT;
2687 2709
2688 XFLOAT_INIT (val, float_value); 2710 XFLOAT_INIT (val, float_value);
2689 eassert (!FLOAT_MARKED_P (XFLOAT (val))); 2711 eassert (!XFLOAT_MARKED_P (XFLOAT (val)));
2690 consing_since_gc += sizeof (struct Lisp_Float); 2712 consing_since_gc += sizeof (struct Lisp_Float);
2691 floats_consed++; 2713 floats_consed++;
2692 total_free_floats--; 2714 total_free_floats--;
@@ -2711,7 +2733,8 @@ make_float (double float_value)
2711 / (sizeof (struct Lisp_Cons) * CHAR_BIT + 1)) 2733 / (sizeof (struct Lisp_Cons) * CHAR_BIT + 1))
2712 2734
2713#define CONS_BLOCK(fptr) \ 2735#define CONS_BLOCK(fptr) \
2714 ((struct cons_block *) ((uintptr_t) (fptr) & ~(BLOCK_ALIGN - 1))) 2736 (eassert (!pdumper_object_p (fptr)), \
2737 ((struct cons_block *) ((uintptr_t) (fptr) & ~(BLOCK_ALIGN - 1))))
2715 2738
2716#define CONS_INDEX(fptr) \ 2739#define CONS_INDEX(fptr) \
2717 (((uintptr_t) (fptr) & (BLOCK_ALIGN - 1)) / sizeof (struct Lisp_Cons)) 2740 (((uintptr_t) (fptr) & (BLOCK_ALIGN - 1)) / sizeof (struct Lisp_Cons))
@@ -2724,13 +2747,13 @@ struct cons_block
2724 struct cons_block *next; 2747 struct cons_block *next;
2725}; 2748};
2726 2749
2727#define CONS_MARKED_P(fptr) \ 2750#define XCONS_MARKED_P(fptr) \
2728 GETMARKBIT (CONS_BLOCK (fptr), CONS_INDEX ((fptr))) 2751 GETMARKBIT (CONS_BLOCK (fptr), CONS_INDEX ((fptr)))
2729 2752
2730#define CONS_MARK(fptr) \ 2753#define XMARK_CONS(fptr) \
2731 SETMARKBIT (CONS_BLOCK (fptr), CONS_INDEX ((fptr))) 2754 SETMARKBIT (CONS_BLOCK (fptr), CONS_INDEX ((fptr)))
2732 2755
2733#define CONS_UNMARK(fptr) \ 2756#define XUNMARK_CONS(fptr) \
2734 UNSETMARKBIT (CONS_BLOCK (fptr), CONS_INDEX ((fptr))) 2757 UNSETMARKBIT (CONS_BLOCK (fptr), CONS_INDEX ((fptr)))
2735 2758
2736/* Current cons_block. */ 2759/* Current cons_block. */
@@ -2803,7 +2826,7 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
2803 2826
2804 XSETCAR (val, car); 2827 XSETCAR (val, car);
2805 XSETCDR (val, cdr); 2828 XSETCDR (val, cdr);
2806 eassert (!CONS_MARKED_P (XCONS (val))); 2829 eassert (!XCONS_MARKED_P (XCONS (val)));
2807 consing_since_gc += sizeof (struct Lisp_Cons); 2830 consing_since_gc += sizeof (struct Lisp_Cons);
2808 total_free_conses--; 2831 total_free_conses--;
2809 cons_cells_consed++; 2832 cons_cells_consed++;
@@ -3103,6 +3126,7 @@ static void
3103init_vectors (void) 3126init_vectors (void)
3104{ 3127{
3105 zero_vector = make_pure_vector (0); 3128 zero_vector = make_pure_vector (0);
3129 staticpro (&zero_vector);
3106} 3130}
3107 3131
3108/* Allocate vector from a vector block. */ 3132/* Allocate vector from a vector block. */
@@ -3173,17 +3197,17 @@ allocate_vector_from_block (ptrdiff_t nbytes)
3173 3197
3174/* Return the memory footprint of V in bytes. */ 3198/* Return the memory footprint of V in bytes. */
3175 3199
3176static ptrdiff_t 3200ptrdiff_t
3177vector_nbytes (struct Lisp_Vector *v) 3201vectorlike_nbytes (const union vectorlike_header *hdr)
3178{ 3202{
3179 ptrdiff_t size = v->header.size & ~ARRAY_MARK_FLAG; 3203 ptrdiff_t size = hdr->size & ~ARRAY_MARK_FLAG;
3180 ptrdiff_t nwords; 3204 ptrdiff_t nwords;
3181 3205
3182 if (size & PSEUDOVECTOR_FLAG) 3206 if (size & PSEUDOVECTOR_FLAG)
3183 { 3207 {
3184 if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR)) 3208 if (PSEUDOVECTOR_TYPEP (hdr, PVEC_BOOL_VECTOR))
3185 { 3209 {
3186 struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) v; 3210 struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) hdr;
3187 ptrdiff_t word_bytes = (bool_vector_words (bv->size) 3211 ptrdiff_t word_bytes = (bool_vector_words (bv->size)
3188 * sizeof (bits_word)); 3212 * sizeof (bits_word));
3189 ptrdiff_t boolvec_bytes = bool_header_size + word_bytes; 3213 ptrdiff_t boolvec_bytes = bool_header_size + word_bytes;
@@ -3281,9 +3305,9 @@ sweep_vectors (void)
3281 for (vector = (struct Lisp_Vector *) block->data; 3305 for (vector = (struct Lisp_Vector *) block->data;
3282 VECTOR_IN_BLOCK (vector, block); vector = next) 3306 VECTOR_IN_BLOCK (vector, block); vector = next)
3283 { 3307 {
3284 if (VECTOR_MARKED_P (vector)) 3308 if (XVECTOR_MARKED_P (vector))
3285 { 3309 {
3286 VECTOR_UNMARK (vector); 3310 XUNMARK_VECTOR (vector);
3287 total_vectors++; 3311 total_vectors++;
3288 ptrdiff_t nbytes = vector_nbytes (vector); 3312 ptrdiff_t nbytes = vector_nbytes (vector);
3289 total_vector_slots += nbytes / word_size; 3313 total_vector_slots += nbytes / word_size;
@@ -3304,7 +3328,7 @@ sweep_vectors (void)
3304 total_bytes += nbytes; 3328 total_bytes += nbytes;
3305 next = ADVANCE (next, nbytes); 3329 next = ADVANCE (next, nbytes);
3306 } 3330 }
3307 while (VECTOR_IN_BLOCK (next, block) && !VECTOR_MARKED_P (next)); 3331 while (VECTOR_IN_BLOCK (next, block) && !vector_marked_p (next));
3308 3332
3309 eassert (total_bytes % roundup_size == 0); 3333 eassert (total_bytes % roundup_size == 0);
3310 3334
@@ -3335,9 +3359,9 @@ sweep_vectors (void)
3335 for (lv = large_vectors; lv; lv = *lvprev) 3359 for (lv = large_vectors; lv; lv = *lvprev)
3336 { 3360 {
3337 vector = large_vector_vec (lv); 3361 vector = large_vector_vec (lv);
3338 if (VECTOR_MARKED_P (vector)) 3362 if (XVECTOR_MARKED_P (vector))
3339 { 3363 {
3340 VECTOR_UNMARK (vector); 3364 XUNMARK_VECTOR (vector);
3341 total_vectors++; 3365 total_vectors++;
3342 if (vector->header.size & PSEUDOVECTOR_FLAG) 3366 if (vector->header.size & PSEUDOVECTOR_FLAG)
3343 total_vector_slots += vector_nbytes (vector) / word_size; 3367 total_vector_slots += vector_nbytes (vector) / word_size;
@@ -3847,7 +3871,7 @@ mark_finalizer_list (struct Lisp_Finalizer *head)
3847 finalizer != head; 3871 finalizer != head;
3848 finalizer = finalizer->next) 3872 finalizer = finalizer->next)
3849 { 3873 {
3850 VECTOR_MARK (finalizer); 3874 set_vectorlike_marked (&finalizer->header);
3851 mark_object (finalizer->function); 3875 mark_object (finalizer->function);
3852 } 3876 }
3853} 3877}
@@ -3864,7 +3888,8 @@ queue_doomed_finalizers (struct Lisp_Finalizer *dest,
3864 while (finalizer != src) 3888 while (finalizer != src)
3865 { 3889 {
3866 struct Lisp_Finalizer *next = finalizer->next; 3890 struct Lisp_Finalizer *next = finalizer->next;
3867 if (!VECTOR_MARKED_P (finalizer) && !NILP (finalizer->function)) 3891 if (!vectorlike_marked_p (&finalizer->header)
3892 && !NILP (finalizer->function))
3868 { 3893 {
3869 unchain_finalizer (finalizer); 3894 unchain_finalizer (finalizer);
3870 finalizer_insert (dest, finalizer); 3895 finalizer_insert (dest, finalizer);
@@ -3885,6 +3910,9 @@ static void
3885run_finalizer_function (Lisp_Object function) 3910run_finalizer_function (Lisp_Object function)
3886{ 3911{
3887 ptrdiff_t count = SPECPDL_INDEX (); 3912 ptrdiff_t count = SPECPDL_INDEX ();
3913#ifdef HAVE_PDUMPER
3914 ++number_finalizers_run;
3915#endif
3888 3916
3889 specbind (Qinhibit_quit, Qt); 3917 specbind (Qinhibit_quit, Qt);
3890 internal_condition_case_1 (call0, function, Qt, run_finalizer_handler); 3918 internal_condition_case_1 (call0, function, Qt, run_finalizer_handler);
@@ -3929,6 +3957,126 @@ FUNCTION. FUNCTION will be run once per finalizer object. */)
3929 3957
3930 3958
3931/************************************************************************ 3959/************************************************************************
3960 Mark bit access functions
3961 ************************************************************************/
3962
3963/* With the rare exception of functions implementing block-based
3964 allocation of various types, you should not directly test or set GC
3965 mark bits on objects. Some objects might live in special memory
3966 regions (e.g., a dump image) and might store their mark bits
3967 elsewhere. */
3968
3969static bool
3970vector_marked_p (const struct Lisp_Vector *v)
3971{
3972 if (pdumper_object_p (v))
3973 {
3974 /* Look at cold_start first so that we don't have to fault in
3975 the vector header just to tell that it's a bool vector. */
3976 if (pdumper_cold_object_p (v))
3977 {
3978 eassert (PSEUDOVECTOR_TYPE (v) == PVEC_BOOL_VECTOR);
3979 return true;
3980 }
3981 return pdumper_marked_p (v);
3982 }
3983 return XVECTOR_MARKED_P (v);
3984}
3985
3986static void
3987set_vector_marked (struct Lisp_Vector *v)
3988{
3989 if (pdumper_object_p (v))
3990 {
3991 eassert (PSEUDOVECTOR_TYPE (v) != PVEC_BOOL_VECTOR);
3992 pdumper_set_marked (v);
3993 }
3994 else
3995 XMARK_VECTOR (v);
3996}
3997
3998static bool
3999vectorlike_marked_p (const union vectorlike_header *header)
4000{
4001 return vector_marked_p ((const struct Lisp_Vector *) header);
4002}
4003
4004static void
4005set_vectorlike_marked (union vectorlike_header *header)
4006{
4007 set_vector_marked ((struct Lisp_Vector *) header);
4008}
4009
4010static bool
4011cons_marked_p (const struct Lisp_Cons *c)
4012{
4013 return pdumper_object_p (c)
4014 ? pdumper_marked_p (c)
4015 : XCONS_MARKED_P (c);
4016}
4017
4018static void
4019set_cons_marked (struct Lisp_Cons *c)
4020{
4021 if (pdumper_object_p (c))
4022 pdumper_set_marked (c);
4023 else
4024 XMARK_CONS (c);
4025}
4026
4027static bool
4028string_marked_p (const struct Lisp_String *s)
4029{
4030 return pdumper_object_p (s)
4031 ? pdumper_marked_p (s)
4032 : XSTRING_MARKED_P (s);
4033}
4034
4035static void
4036set_string_marked (struct Lisp_String *s)
4037{
4038 if (pdumper_object_p (s))
4039 pdumper_set_marked (s);
4040 else
4041 XMARK_STRING (s);
4042}
4043
4044static bool
4045symbol_marked_p (const struct Lisp_Symbol *s)
4046{
4047 return pdumper_object_p (s)
4048 ? pdumper_marked_p (s)
4049 : s->u.s.gcmarkbit;
4050}
4051
4052static void
4053set_symbol_marked (struct Lisp_Symbol *s)
4054{
4055 if (pdumper_object_p (s))
4056 pdumper_set_marked (s);
4057 else
4058 s->u.s.gcmarkbit = true;
4059}
4060
4061static bool
4062interval_marked_p (INTERVAL i)
4063{
4064 return pdumper_object_p (i)
4065 ? pdumper_marked_p (i)
4066 : i->gcmarkbit;
4067}
4068
4069static void
4070set_interval_marked (INTERVAL i)
4071{
4072 if (pdumper_object_p (i))
4073 pdumper_set_marked (i);
4074 else
4075 i->gcmarkbit = true;
4076}
4077
4078
4079/************************************************************************
3932 Memory Full Handling 4080 Memory Full Handling
3933 ************************************************************************/ 4081 ************************************************************************/
3934 4082
@@ -4626,14 +4774,29 @@ static void
4626mark_maybe_object (Lisp_Object obj) 4774mark_maybe_object (Lisp_Object obj)
4627{ 4775{
4628#if USE_VALGRIND 4776#if USE_VALGRIND
4629 if (valgrind_p) 4777 VALGRIND_MAKE_MEM_DEFINED (&obj, sizeof (obj));
4630 VALGRIND_MAKE_MEM_DEFINED (&obj, sizeof (obj));
4631#endif 4778#endif
4632 4779
4633 if (FIXNUMP (obj)) 4780 if (FIXNUMP (obj))
4634 return; 4781 return;
4635 4782
4636 void *po = XPNTR (obj); 4783 void *po = XPNTR (obj);
4784
4785 /* If the pointer is in the dumped image and the dump has a record
4786 of the object starting at the place where the pointer points, we
4787 definitely have an object. If the pointer is in the dumped image
4788 and the dump has no idea what the pointer is pointing at, we
4789 definitely _don't_ have an object. */
4790 if (pdumper_object_p (po))
4791 {
4792 /* Don't use pdumper_object_p_precise here! It doesn't check the
4793 tag bits. OBJ here might be complete garbage, so we need to
4794 verify both the pointer and the tag. */
4795 if (XTYPE (obj) == pdumper_find_object_type (po))
4796 mark_object (obj);
4797 return;
4798 }
4799
4637 struct mem_node *m = mem_find (po); 4800 struct mem_node *m = mem_find (po);
4638 4801
4639 if (m != MEM_NIL) 4802 if (m != MEM_NIL)
@@ -4703,9 +4866,8 @@ mark_maybe_pointer (void *p)
4703{ 4866{
4704 struct mem_node *m; 4867 struct mem_node *m;
4705 4868
4706#if USE_VALGRIND 4869#ifdef USE_VALGRIND
4707 if (valgrind_p) 4870 VALGRIND_MAKE_MEM_DEFINED (&p, sizeof (p));
4708 VALGRIND_MAKE_MEM_DEFINED (&p, sizeof (p));
4709#endif 4871#endif
4710 4872
4711 if (sizeof (Lisp_Object) == sizeof (void *) || !HAVE_MODULES) 4873 if (sizeof (Lisp_Object) == sizeof (void *) || !HAVE_MODULES)
@@ -4720,6 +4882,17 @@ mark_maybe_pointer (void *p)
4720 p = (void *) ((uintptr_t) p & ~((1 << GCTYPEBITS) - 1)); 4882 p = (void *) ((uintptr_t) p & ~((1 << GCTYPEBITS) - 1));
4721 } 4883 }
4722 4884
4885 if (pdumper_object_p (p))
4886 {
4887 enum Lisp_Type type = pdumper_find_object_type (p);
4888 if (type != PDUMPER_NO_OBJECT)
4889 mark_object ((type == Lisp_Symbol)
4890 ? make_lisp_symbol(p)
4891 : make_lisp_ptr(p, type));
4892 /* See mark_maybe_object for why we can confidently return. */
4893 return;
4894 }
4895
4723 m = mem_find (p); 4896 m = mem_find (p);
4724 if (m != MEM_NIL) 4897 if (m != MEM_NIL)
4725 { 4898 {
@@ -5076,6 +5249,12 @@ valid_pointer_p (void *p)
5076 return p ? -1 : 0; 5249 return p ? -1 : 0;
5077 5250
5078 int fd[2]; 5251 int fd[2];
5252 static int under_rr_state;
5253
5254 if (!under_rr_state)
5255 under_rr_state = getenv ("RUNNING_UNDER_RR") ? -1 : 1;
5256 if (under_rr_state < 0)
5257 return under_rr_state;
5079 5258
5080 /* Obviously, we cannot just access it (we would SEGV trying), so we 5259 /* Obviously, we cannot just access it (we would SEGV trying), so we
5081 trick the o/s to tell us whether p is a valid pointer. 5260 trick the o/s to tell us whether p is a valid pointer.
@@ -5115,6 +5294,9 @@ valid_lisp_object_p (Lisp_Object obj)
5115 if (p == &buffer_defaults || p == &buffer_local_symbols) 5294 if (p == &buffer_defaults || p == &buffer_local_symbols)
5116 return 2; 5295 return 2;
5117 5296
5297 if (pdumper_object_p (p))
5298 return pdumper_object_p_precise (p) ? 1 : 0;
5299
5118 struct mem_node *m = mem_find (p); 5300 struct mem_node *m = mem_find (p);
5119 5301
5120 if (m == MEM_NIL) 5302 if (m == MEM_NIL)
@@ -5324,7 +5506,7 @@ make_pure_c_string (const char *data, ptrdiff_t nchars)
5324 Lisp_Object string; 5506 Lisp_Object string;
5325 struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String); 5507 struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
5326 s->u.s.size = nchars; 5508 s->u.s.size = nchars;
5327 s->u.s.size_byte = -1; 5509 s->u.s.size_byte = -2;
5328 s->u.s.data = (unsigned char *) data; 5510 s->u.s.data = (unsigned char *) data;
5329 s->u.s.intervals = NULL; 5511 s->u.s.intervals = NULL;
5330 XSETSTRING (string, s); 5512 XSETSTRING (string, s);
@@ -5617,7 +5799,7 @@ compact_font_cache_entry (Lisp_Object entry)
5617 5799
5618 /* Consider OBJ if it is (font-spec . [font-entity font-entity ...]). */ 5800 /* Consider OBJ if it is (font-spec . [font-entity font-entity ...]). */
5619 if (CONSP (obj) && GC_FONT_SPEC_P (XCAR (obj)) 5801 if (CONSP (obj) && GC_FONT_SPEC_P (XCAR (obj))
5620 && !VECTOR_MARKED_P (GC_XFONT_SPEC (XCAR (obj))) 5802 && !vectorlike_marked_p (&GC_XFONT_SPEC (XCAR (obj))->header)
5621 /* Don't use VECTORP here, as that calls ASIZE, which could 5803 /* Don't use VECTORP here, as that calls ASIZE, which could
5622 hit assertion violation during GC. */ 5804 hit assertion violation during GC. */
5623 && (VECTORLIKEP (XCDR (obj)) 5805 && (VECTORLIKEP (XCDR (obj))
@@ -5633,7 +5815,8 @@ compact_font_cache_entry (Lisp_Object entry)
5633 { 5815 {
5634 Lisp_Object objlist; 5816 Lisp_Object objlist;
5635 5817
5636 if (VECTOR_MARKED_P (GC_XFONT_ENTITY (AREF (obj_cdr, i)))) 5818 if (vectorlike_marked_p (
5819 &GC_XFONT_ENTITY (AREF (obj_cdr, i))->header))
5637 break; 5820 break;
5638 5821
5639 objlist = AREF (AREF (obj_cdr, i), FONT_OBJLIST_INDEX); 5822 objlist = AREF (AREF (obj_cdr, i), FONT_OBJLIST_INDEX);
@@ -5643,7 +5826,7 @@ compact_font_cache_entry (Lisp_Object entry)
5643 struct font *font = GC_XFONT_OBJECT (val); 5826 struct font *font = GC_XFONT_OBJECT (val);
5644 5827
5645 if (!NILP (AREF (val, FONT_TYPE_INDEX)) 5828 if (!NILP (AREF (val, FONT_TYPE_INDEX))
5646 && VECTOR_MARKED_P(font)) 5829 && vectorlike_marked_p(&font->header))
5647 break; 5830 break;
5648 } 5831 }
5649 if (CONSP (objlist)) 5832 if (CONSP (objlist))
@@ -5712,7 +5895,7 @@ compact_undo_list (Lisp_Object list)
5712 { 5895 {
5713 if (CONSP (XCAR (tail)) 5896 if (CONSP (XCAR (tail))
5714 && MARKERP (XCAR (XCAR (tail))) 5897 && MARKERP (XCAR (XCAR (tail)))
5715 && !VECTOR_MARKED_P (XMARKER (XCAR (XCAR (tail))))) 5898 && !vectorlike_marked_p (&XMARKER (XCAR (XCAR (tail)))->header))
5716 *prev = XCDR (tail); 5899 *prev = XCDR (tail);
5717 else 5900 else
5718 prev = xcdr_addr (tail); 5901 prev = xcdr_addr (tail);
@@ -5745,6 +5928,105 @@ mark_pinned_symbols (void)
5745 } 5928 }
5746} 5929}
5747 5930
5931static void
5932visit_vectorlike_root (struct gc_root_visitor visitor,
5933 struct Lisp_Vector *ptr,
5934 enum gc_root_type type)
5935{
5936 ptrdiff_t size = ptr->header.size;
5937 ptrdiff_t i;
5938
5939 if (size & PSEUDOVECTOR_FLAG)
5940 size &= PSEUDOVECTOR_SIZE_MASK;
5941 for (i = 0; i < size; i++)
5942 visitor.visit (&ptr->contents[i], type, visitor.data);
5943}
5944
5945static void
5946visit_buffer_root (struct gc_root_visitor visitor,
5947 struct buffer *buffer,
5948 enum gc_root_type type)
5949{
5950 /* Buffers that are roots don't have intervals, an undo list, or
5951 other constructs that real buffers have. */
5952 eassert (buffer->base_buffer == NULL);
5953 eassert (buffer->overlays_before == NULL);
5954 eassert (buffer->overlays_after == NULL);
5955
5956 /* Visit the buffer-locals. */
5957 visit_vectorlike_root (visitor, (struct Lisp_Vector *) buffer, type);
5958}
5959
5960/* Visit GC roots stored in the Emacs data section. Used by both core
5961 GC and by the portable dumping code.
5962
5963 There are other GC roots of course, but these roots are dynamic
5964 runtime data structures that pdump doesn't care about and so we can
5965 continue to mark those directly in garbage_collect_1. */
5966void
5967visit_static_gc_roots (struct gc_root_visitor visitor)
5968{
5969 visit_buffer_root (visitor,
5970 &buffer_defaults,
5971 GC_ROOT_BUFFER_LOCAL_DEFAULT);
5972 visit_buffer_root (visitor,
5973 &buffer_local_symbols,
5974 GC_ROOT_BUFFER_LOCAL_NAME);
5975
5976 for (int i = 0; i < ARRAYELTS (lispsym); i++)
5977 {
5978 Lisp_Object sptr = builtin_lisp_symbol (i);
5979 visitor.visit (&sptr, GC_ROOT_C_SYMBOL, visitor.data);
5980 }
5981
5982 for (int i = 0; i < staticidx; i++)
5983 visitor.visit (staticvec[i], GC_ROOT_STATICPRO, visitor.data);
5984}
5985
5986static void
5987mark_object_root_visitor (Lisp_Object *root_ptr,
5988 enum gc_root_type type,
5989 void *data)
5990{
5991 mark_object (*root_ptr);
5992}
5993
5994/* List of weak hash tables we found during marking the Lisp heap.
5995 Will be NULL on entry to garbage_collect_1 and after it
5996 returns. */
5997static struct Lisp_Hash_Table *weak_hash_tables;
5998
5999NO_INLINE /* For better stack traces */
6000static void
6001mark_and_sweep_weak_table_contents (void)
6002{
6003 struct Lisp_Hash_Table *h;
6004 bool marked;
6005
6006 /* Mark all keys and values that are in use. Keep on marking until
6007 there is no more change. This is necessary for cases like
6008 value-weak table A containing an entry X -> Y, where Y is used in a
6009 key-weak table B, Z -> Y. If B comes after A in the list of weak
6010 tables, X -> Y might be removed from A, although when looking at B
6011 one finds that it shouldn't. */
6012 do
6013 {
6014 marked = false;
6015 for (h = weak_hash_tables; h; h = h->next_weak)
6016 marked |= sweep_weak_table (h, false);
6017 }
6018 while (marked);
6019
6020 /* Remove hash table entries that aren't used. */
6021 while (weak_hash_tables)
6022 {
6023 h = weak_hash_tables;
6024 weak_hash_tables = h->next_weak;
6025 h->next_weak = NULL;
6026 sweep_weak_table (h, true);
6027 }
6028}
6029
5748/* Subroutine of Fgarbage_collect that does most of the work. It is a 6030/* Subroutine of Fgarbage_collect that does most of the work. It is a
5749 separate function so that we could limit mark_stack in searching 6031 separate function so that we could limit mark_stack in searching
5750 the stack frames below this function, thus avoiding the rare cases 6032 the stack frames below this function, thus avoiding the rare cases
@@ -5757,13 +6039,14 @@ garbage_collect_1 (void *end)
5757{ 6039{
5758 struct buffer *nextb; 6040 struct buffer *nextb;
5759 char stack_top_variable; 6041 char stack_top_variable;
5760 ptrdiff_t i;
5761 bool message_p; 6042 bool message_p;
5762 ptrdiff_t count = SPECPDL_INDEX (); 6043 ptrdiff_t count = SPECPDL_INDEX ();
5763 struct timespec start; 6044 struct timespec start;
5764 Lisp_Object retval = Qnil; 6045 Lisp_Object retval = Qnil;
5765 byte_ct tot_before = 0; 6046 byte_ct tot_before = 0;
5766 6047
6048 eassert (weak_hash_tables == NULL);
6049
5767 /* Can't GC if pure storage overflowed because we can't determine 6050 /* Can't GC if pure storage overflowed because we can't determine
5768 if something is a pure object or not. */ 6051 if something is a pure object or not. */
5769 if (pure_bytes_used_before_overflow) 6052 if (pure_bytes_used_before_overflow)
@@ -5839,14 +6122,10 @@ garbage_collect_1 (void *end)
5839 6122
5840 /* Mark all the special slots that serve as the roots of accessibility. */ 6123 /* Mark all the special slots that serve as the roots of accessibility. */
5841 6124
5842 mark_buffer (&buffer_defaults); 6125 struct gc_root_visitor visitor;
5843 mark_buffer (&buffer_local_symbols); 6126 memset (&visitor, 0, sizeof (visitor));
5844 6127 visitor.visit = mark_object_root_visitor;
5845 for (i = 0; i < ARRAYELTS (lispsym); i++) 6128 visit_static_gc_roots (visitor);
5846 mark_object (builtin_lisp_symbol (i));
5847
5848 for (i = 0; i < staticidx; i++)
5849 mark_object (*staticvec[i]);
5850 6129
5851 mark_pinned_objects (); 6130 mark_pinned_objects ();
5852 mark_pinned_symbols (); 6131 mark_pinned_symbols ();
@@ -5891,11 +6170,11 @@ garbage_collect_1 (void *end)
5891 queue_doomed_finalizers (&doomed_finalizers, &finalizers); 6170 queue_doomed_finalizers (&doomed_finalizers, &finalizers);
5892 mark_finalizer_list (&doomed_finalizers); 6171 mark_finalizer_list (&doomed_finalizers);
5893 6172
5894 gc_sweep (); 6173 /* Must happen after all other marking and before gc_sweep. */
6174 mark_and_sweep_weak_table_contents ();
6175 eassert (weak_hash_tables == NULL);
5895 6176
5896 /* Clear the mark bits that we set in certain root slots. */ 6177 gc_sweep ();
5897 VECTOR_UNMARK (&buffer_defaults);
5898 VECTOR_UNMARK (&buffer_local_symbols);
5899 6178
5900 unmark_main_thread (); 6179 unmark_main_thread ();
5901 6180
@@ -6043,7 +6322,7 @@ mark_glyph_matrix (struct glyph_matrix *matrix)
6043 6322
6044 for (; glyph < end_glyph; ++glyph) 6323 for (; glyph < end_glyph; ++glyph)
6045 if (STRINGP (glyph->object) 6324 if (STRINGP (glyph->object)
6046 && !STRING_MARKED_P (XSTRING (glyph->object))) 6325 && !string_marked_p (XSTRING (glyph->object)))
6047 mark_object (glyph->object); 6326 mark_object (glyph->object);
6048 } 6327 }
6049 } 6328 }
@@ -6060,13 +6339,18 @@ static int last_marked_index;
6060ptrdiff_t mark_object_loop_halt EXTERNALLY_VISIBLE; 6339ptrdiff_t mark_object_loop_halt EXTERNALLY_VISIBLE;
6061 6340
6062static void 6341static void
6063mark_vectorlike (struct Lisp_Vector *ptr) 6342mark_vectorlike (union vectorlike_header *header)
6064{ 6343{
6344 struct Lisp_Vector *ptr = (struct Lisp_Vector *) header;
6065 ptrdiff_t size = ptr->header.size; 6345 ptrdiff_t size = ptr->header.size;
6066 ptrdiff_t i; 6346 ptrdiff_t i;
6067 6347
6068 eassert (!VECTOR_MARKED_P (ptr)); 6348 eassert (!vector_marked_p (ptr));
6069 VECTOR_MARK (ptr); /* Else mark it. */ 6349
6350 /* Bool vectors have a different case in mark_object. */
6351 eassert (PSEUDOVECTOR_TYPE (ptr) != PVEC_BOOL_VECTOR);
6352
6353 set_vector_marked (ptr); /* Else mark it. */
6070 if (size & PSEUDOVECTOR_FLAG) 6354 if (size & PSEUDOVECTOR_FLAG)
6071 size &= PSEUDOVECTOR_SIZE_MASK; 6355 size &= PSEUDOVECTOR_SIZE_MASK;
6072 6356
@@ -6089,17 +6373,18 @@ mark_char_table (struct Lisp_Vector *ptr, enum pvec_type pvectype)
6089 /* Consult the Lisp_Sub_Char_Table layout before changing this. */ 6373 /* Consult the Lisp_Sub_Char_Table layout before changing this. */
6090 int i, idx = (pvectype == PVEC_SUB_CHAR_TABLE ? SUB_CHAR_TABLE_OFFSET : 0); 6374 int i, idx = (pvectype == PVEC_SUB_CHAR_TABLE ? SUB_CHAR_TABLE_OFFSET : 0);
6091 6375
6092 eassert (!VECTOR_MARKED_P (ptr)); 6376 eassert (!vector_marked_p (ptr));
6093 VECTOR_MARK (ptr); 6377 set_vector_marked (ptr);
6094 for (i = idx; i < size; i++) 6378 for (i = idx; i < size; i++)
6095 { 6379 {
6096 Lisp_Object val = ptr->contents[i]; 6380 Lisp_Object val = ptr->contents[i];
6097 6381
6098 if (FIXNUMP (val) || (SYMBOLP (val) && XSYMBOL (val)->u.s.gcmarkbit)) 6382 if (FIXNUMP (val) ||
6383 (SYMBOLP (val) && symbol_marked_p (XSYMBOL (val))))
6099 continue; 6384 continue;
6100 if (SUB_CHAR_TABLE_P (val)) 6385 if (SUB_CHAR_TABLE_P (val))
6101 { 6386 {
6102 if (! VECTOR_MARKED_P (XVECTOR (val))) 6387 if (! vector_marked_p (XVECTOR (val)))
6103 mark_char_table (XVECTOR (val), PVEC_SUB_CHAR_TABLE); 6388 mark_char_table (XVECTOR (val), PVEC_SUB_CHAR_TABLE);
6104 } 6389 }
6105 else 6390 else
@@ -6113,7 +6398,7 @@ mark_compiled (struct Lisp_Vector *ptr)
6113{ 6398{
6114 int i, size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK; 6399 int i, size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK;
6115 6400
6116 VECTOR_MARK (ptr); 6401 set_vector_marked (ptr);
6117 for (i = 0; i < size; i++) 6402 for (i = 0; i < size; i++)
6118 if (i != COMPILED_CONSTANTS) 6403 if (i != COMPILED_CONSTANTS)
6119 mark_object (ptr->contents[i]); 6404 mark_object (ptr->contents[i]);
@@ -6125,12 +6410,12 @@ mark_compiled (struct Lisp_Vector *ptr)
6125static void 6410static void
6126mark_overlay (struct Lisp_Overlay *ptr) 6411mark_overlay (struct Lisp_Overlay *ptr)
6127{ 6412{
6128 for (; ptr && !VECTOR_MARKED_P (ptr); ptr = ptr->next) 6413 for (; ptr && !vectorlike_marked_p (&ptr->header); ptr = ptr->next)
6129 { 6414 {
6130 VECTOR_MARK (ptr); 6415 set_vectorlike_marked (&ptr->header);
6131 /* These two are always markers and can be marked fast. */ 6416 /* These two are always markers and can be marked fast. */
6132 VECTOR_MARK (XMARKER (ptr->start)); 6417 set_vectorlike_marked (&XMARKER (ptr->start)->header);
6133 VECTOR_MARK (XMARKER (ptr->end)); 6418 set_vectorlike_marked (&XMARKER (ptr->end)->header);
6134 mark_object (ptr->plist); 6419 mark_object (ptr->plist);
6135 } 6420 }
6136} 6421}
@@ -6141,11 +6426,11 @@ static void
6141mark_buffer (struct buffer *buffer) 6426mark_buffer (struct buffer *buffer)
6142{ 6427{
6143 /* This is handled much like other pseudovectors... */ 6428 /* This is handled much like other pseudovectors... */
6144 mark_vectorlike ((struct Lisp_Vector *) buffer); 6429 mark_vectorlike (&buffer->header);
6145 6430
6146 /* ...but there are some buffer-specific things. */ 6431 /* ...but there are some buffer-specific things. */
6147 6432
6148 MARK_INTERVAL_TREE (buffer_intervals (buffer)); 6433 mark_interval_tree (buffer_intervals (buffer));
6149 6434
6150 /* For now, we just don't mark the undo_list. It's done later in 6435 /* For now, we just don't mark the undo_list. It's done later in
6151 a special way just before the sweep phase, and after stripping 6436 a special way just before the sweep phase, and after stripping
@@ -6155,7 +6440,8 @@ mark_buffer (struct buffer *buffer)
6155 mark_overlay (buffer->overlays_after); 6440 mark_overlay (buffer->overlays_after);
6156 6441
6157 /* If this is an indirect buffer, mark its base buffer. */ 6442 /* If this is an indirect buffer, mark its base buffer. */
6158 if (buffer->base_buffer && !VECTOR_MARKED_P (buffer->base_buffer)) 6443 if (buffer->base_buffer &&
6444 !vectorlike_marked_p (&buffer->base_buffer->header))
6159 mark_buffer (buffer->base_buffer); 6445 mark_buffer (buffer->base_buffer);
6160} 6446}
6161 6447
@@ -6174,8 +6460,8 @@ mark_face_cache (struct face_cache *c)
6174 6460
6175 if (face) 6461 if (face)
6176 { 6462 {
6177 if (face->font && !VECTOR_MARKED_P (face->font)) 6463 if (face->font && !vectorlike_marked_p (&face->font->header))
6178 mark_vectorlike ((struct Lisp_Vector *) face->font); 6464 mark_vectorlike (&face->font->header);
6179 6465
6180 for (j = 0; j < LFACE_VECTOR_SIZE; ++j) 6466 for (j = 0; j < LFACE_VECTOR_SIZE; ++j)
6181 mark_object (face->lface[j]); 6467 mark_object (face->lface[j]);
@@ -6206,7 +6492,7 @@ mark_discard_killed_buffers (Lisp_Object list)
6206{ 6492{
6207 Lisp_Object tail, *prev = &list; 6493 Lisp_Object tail, *prev = &list;
6208 6494
6209 for (tail = list; CONSP (tail) && !CONS_MARKED_P (XCONS (tail)); 6495 for (tail = list; CONSP (tail) && !cons_marked_p (XCONS (tail));
6210 tail = XCDR (tail)) 6496 tail = XCDR (tail))
6211 { 6497 {
6212 Lisp_Object tem = XCAR (tail); 6498 Lisp_Object tem = XCAR (tail);
@@ -6216,7 +6502,7 @@ mark_discard_killed_buffers (Lisp_Object list)
6216 *prev = XCDR (tail); 6502 *prev = XCDR (tail);
6217 else 6503 else
6218 { 6504 {
6219 CONS_MARK (XCONS (tail)); 6505 set_cons_marked (XCONS (tail));
6220 mark_object (XCAR (tail)); 6506 mark_object (XCAR (tail));
6221 prev = xcdr_addr (tail); 6507 prev = xcdr_addr (tail);
6222 } 6508 }
@@ -6225,6 +6511,72 @@ mark_discard_killed_buffers (Lisp_Object list)
6225 return list; 6511 return list;
6226} 6512}
6227 6513
6514static void
6515mark_frame (struct Lisp_Vector *ptr)
6516{
6517 struct frame *f = (struct frame *) ptr;
6518 mark_vectorlike (&ptr->header);
6519 mark_face_cache (f->face_cache);
6520#ifdef HAVE_WINDOW_SYSTEM
6521 if (FRAME_WINDOW_P (f) && FRAME_X_OUTPUT (f))
6522 {
6523 struct font *font = FRAME_FONT (f);
6524
6525 if (font && !vectorlike_marked_p (&font->header))
6526 mark_vectorlike (&font->header);
6527 }
6528#endif
6529}
6530
6531static void
6532mark_window (struct Lisp_Vector *ptr)
6533{
6534 struct window *w = (struct window *) ptr;
6535
6536 mark_vectorlike (&ptr->header);
6537
6538 /* Mark glyph matrices, if any. Marking window
6539 matrices is sufficient because frame matrices
6540 use the same glyph memory. */
6541 if (w->current_matrix)
6542 {
6543 mark_glyph_matrix (w->current_matrix);
6544 mark_glyph_matrix (w->desired_matrix);
6545 }
6546
6547 /* Filter out killed buffers from both buffer lists
6548 in attempt to help GC to reclaim killed buffers faster.
6549 We can do it elsewhere for live windows, but this is the
6550 best place to do it for dead windows. */
6551 wset_prev_buffers
6552 (w, mark_discard_killed_buffers (w->prev_buffers));
6553 wset_next_buffers
6554 (w, mark_discard_killed_buffers (w->next_buffers));
6555}
6556
6557static void
6558mark_hash_table (struct Lisp_Vector *ptr)
6559{
6560 struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *) ptr;
6561
6562 mark_vectorlike (&h->header);
6563 mark_object (h->test.name);
6564 mark_object (h->test.user_hash_function);
6565 mark_object (h->test.user_cmp_function);
6566 /* If hash table is not weak, mark all keys and values. For weak
6567 tables, mark only the vector and not its contents --- that's what
6568 makes it weak. */
6569 if (NILP (h->weak))
6570 mark_object (h->key_and_value);
6571 else
6572 {
6573 eassert (h->next_weak == NULL);
6574 h->next_weak = weak_hash_tables;
6575 weak_hash_tables = h;
6576 set_vector_marked (XVECTOR (h->key_and_value));
6577 }
6578}
6579
6228/* Determine type of generic Lisp_Object and mark it accordingly. 6580/* Determine type of generic Lisp_Object and mark it accordingly.
6229 6581
6230 This function implements a straightforward depth-first marking 6582 This function implements a straightforward depth-first marking
@@ -6239,7 +6591,7 @@ mark_object (Lisp_Object arg)
6239 register Lisp_Object obj; 6591 register Lisp_Object obj;
6240 void *po; 6592 void *po;
6241#if GC_CHECK_MARKED_OBJECTS 6593#if GC_CHECK_MARKED_OBJECTS
6242 struct mem_node *m; 6594 struct mem_node *m = NULL;
6243#endif 6595#endif
6244 ptrdiff_t cdr_count = 0; 6596 ptrdiff_t cdr_count = 0;
6245 6597
@@ -6262,6 +6614,12 @@ mark_object (Lisp_Object arg)
6262 structure allocated from the heap. */ 6614 structure allocated from the heap. */
6263#define CHECK_ALLOCATED() \ 6615#define CHECK_ALLOCATED() \
6264 do { \ 6616 do { \
6617 if (pdumper_object_p(po)) \
6618 { \
6619 if (!pdumper_object_p_precise (po)) \
6620 emacs_abort (); \
6621 break; \
6622 } \
6265 m = mem_find (po); \ 6623 m = mem_find (po); \
6266 if (m == MEM_NIL) \ 6624 if (m == MEM_NIL) \
6267 emacs_abort (); \ 6625 emacs_abort (); \
@@ -6271,6 +6629,8 @@ mark_object (Lisp_Object arg)
6271 function LIVEP. */ 6629 function LIVEP. */
6272#define CHECK_LIVE(LIVEP) \ 6630#define CHECK_LIVE(LIVEP) \
6273 do { \ 6631 do { \
6632 if (pdumper_object_p(po)) \
6633 break; \
6274 if (!LIVEP (m, po)) \ 6634 if (!LIVEP (m, po)) \
6275 emacs_abort (); \ 6635 emacs_abort (); \
6276 } while (0) 6636 } while (0)
@@ -6305,11 +6665,11 @@ mark_object (Lisp_Object arg)
6305 case Lisp_String: 6665 case Lisp_String:
6306 { 6666 {
6307 register struct Lisp_String *ptr = XSTRING (obj); 6667 register struct Lisp_String *ptr = XSTRING (obj);
6308 if (STRING_MARKED_P (ptr)) 6668 if (string_marked_p (ptr))
6309 break; 6669 break;
6310 CHECK_ALLOCATED_AND_LIVE (live_string_p); 6670 CHECK_ALLOCATED_AND_LIVE (live_string_p);
6311 MARK_STRING (ptr); 6671 set_string_marked (ptr);
6312 MARK_INTERVAL_TREE (ptr->u.s.intervals); 6672 mark_interval_tree (ptr->u.s.intervals);
6313#ifdef GC_CHECK_STRING_BYTES 6673#ifdef GC_CHECK_STRING_BYTES
6314 /* Check that the string size recorded in the string is the 6674 /* Check that the string size recorded in the string is the
6315 same as the one recorded in the sdata structure. */ 6675 same as the one recorded in the sdata structure. */
@@ -6322,22 +6682,25 @@ mark_object (Lisp_Object arg)
6322 { 6682 {
6323 register struct Lisp_Vector *ptr = XVECTOR (obj); 6683 register struct Lisp_Vector *ptr = XVECTOR (obj);
6324 6684
6325 if (VECTOR_MARKED_P (ptr)) 6685 if (vector_marked_p (ptr))
6326 break; 6686 break;
6327 6687
6328#if GC_CHECK_MARKED_OBJECTS 6688#ifdef GC_CHECK_MARKED_OBJECTS
6329 m = mem_find (po); 6689 if (!pdumper_object_p(po))
6330 if (m == MEM_NIL && !SUBRP (obj) && !main_thread_p (po)) 6690 {
6331 emacs_abort (); 6691 m = mem_find (po);
6692 if (m == MEM_NIL && !SUBRP (obj) && !main_thread_p (po))
6693 emacs_abort ();
6694 }
6332#endif /* GC_CHECK_MARKED_OBJECTS */ 6695#endif /* GC_CHECK_MARKED_OBJECTS */
6333 6696
6334 enum pvec_type pvectype 6697 enum pvec_type pvectype
6335 = PSEUDOVECTOR_TYPE (ptr); 6698 = PSEUDOVECTOR_TYPE (ptr);
6336 6699
6337 if (pvectype != PVEC_SUBR 6700 if (pvectype != PVEC_SUBR &&
6338 && pvectype != PVEC_BUFFER 6701 pvectype != PVEC_BUFFER &&
6339 && !main_thread_p (po)) 6702 !main_thread_p (po))
6340 CHECK_LIVE (live_vector_p); 6703 CHECK_LIVE (live_vector_p);
6341 6704
6342 switch (pvectype) 6705 switch (pvectype)
6343 { 6706 {
@@ -6353,77 +6716,28 @@ mark_object (Lisp_Object arg)
6353 } 6716 }
6354#endif /* GC_CHECK_MARKED_OBJECTS */ 6717#endif /* GC_CHECK_MARKED_OBJECTS */
6355 mark_buffer ((struct buffer *) ptr); 6718 mark_buffer ((struct buffer *) ptr);
6356 break; 6719 break;
6357 6720
6358 case PVEC_COMPILED: 6721 case PVEC_COMPILED:
6359 /* Although we could treat this just like a vector, mark_compiled 6722 /* Although we could treat this just like a vector, mark_compiled
6360 returns the COMPILED_CONSTANTS element, which is marked at the 6723 returns the COMPILED_CONSTANTS element, which is marked at the
6361 next iteration of goto-loop here. This is done to avoid a few 6724 next iteration of goto-loop here. This is done to avoid a few
6362 recursive calls to mark_object. */ 6725 recursive calls to mark_object. */
6363 obj = mark_compiled (ptr); 6726 obj = mark_compiled (ptr);
6364 if (!NILP (obj)) 6727 if (!NILP (obj))
6365 goto loop; 6728 goto loop;
6366 break; 6729 break;
6367 6730
6368 case PVEC_FRAME: 6731 case PVEC_FRAME:
6369 { 6732 mark_frame (ptr);
6370 struct frame *f = (struct frame *) ptr; 6733 break;
6371 6734
6372 mark_vectorlike (ptr); 6735 case PVEC_WINDOW:
6373 mark_face_cache (f->face_cache); 6736 mark_window (ptr);
6374#ifdef HAVE_WINDOW_SYSTEM 6737 break;
6375 if (FRAME_WINDOW_P (f) && FRAME_X_OUTPUT (f))
6376 {
6377 struct font *font = FRAME_FONT (f);
6378
6379 if (font && !VECTOR_MARKED_P (font))
6380 mark_vectorlike ((struct Lisp_Vector *) font);
6381 }
6382#endif
6383 }
6384 break;
6385
6386 case PVEC_WINDOW:
6387 {
6388 struct window *w = (struct window *) ptr;
6389
6390 mark_vectorlike (ptr);
6391
6392 /* Mark glyph matrices, if any. Marking window
6393 matrices is sufficient because frame matrices
6394 use the same glyph memory. */
6395 if (w->current_matrix)
6396 {
6397 mark_glyph_matrix (w->current_matrix);
6398 mark_glyph_matrix (w->desired_matrix);
6399 }
6400
6401 /* Filter out killed buffers from both buffer lists
6402 in attempt to help GC to reclaim killed buffers faster.
6403 We can do it elsewhere for live windows, but this is the
6404 best place to do it for dead windows. */
6405 wset_prev_buffers
6406 (w, mark_discard_killed_buffers (w->prev_buffers));
6407 wset_next_buffers
6408 (w, mark_discard_killed_buffers (w->next_buffers));
6409 }
6410 break;
6411 6738
6412 case PVEC_HASH_TABLE: 6739 case PVEC_HASH_TABLE:
6413 { 6740 mark_hash_table (ptr);
6414 struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *) ptr;
6415
6416 mark_vectorlike (ptr);
6417 mark_object (h->test.name);
6418 mark_object (h->test.user_hash_function);
6419 mark_object (h->test.user_cmp_function);
6420 /* If hash table is not weak, mark all keys and values.
6421 For weak tables, mark only the vector. */
6422 if (NILP (h->weak))
6423 mark_object (h->key_and_value);
6424 else
6425 VECTOR_MARK (XVECTOR (h->key_and_value));
6426 }
6427 break; 6741 break;
6428 6742
6429 case PVEC_CHAR_TABLE: 6743 case PVEC_CHAR_TABLE:
@@ -6431,7 +6745,17 @@ mark_object (Lisp_Object arg)
6431 mark_char_table (ptr, (enum pvec_type) pvectype); 6745 mark_char_table (ptr, (enum pvec_type) pvectype);
6432 break; 6746 break;
6433 6747
6434 case PVEC_OVERLAY: 6748 case PVEC_BOOL_VECTOR:
6749 /* bool vectors in a dump are permanently "marked", since
6750 they're in the old section and don't have mark bits.
6751 If we're looking at a dumped bool vector, we should
6752 have aborted above when we called vector_marked_p(), so
6753 we should never get here. */
6754 eassert (!pdumper_object_p (ptr));
6755 set_vector_marked (ptr);
6756 break;
6757
6758 case PVEC_OVERLAY:
6435 mark_overlay (XOVERLAY (obj)); 6759 mark_overlay (XOVERLAY (obj));
6436 break; 6760 break;
6437 6761
@@ -6444,7 +6768,7 @@ mark_object (Lisp_Object arg)
6444 default: 6768 default:
6445 /* A regular vector, or a pseudovector needing no special 6769 /* A regular vector, or a pseudovector needing no special
6446 treatment. */ 6770 treatment. */
6447 mark_vectorlike (ptr); 6771 mark_vectorlike (&ptr->header);
6448 } 6772 }
6449 } 6773 }
6450 break; 6774 break;
@@ -6453,10 +6777,10 @@ mark_object (Lisp_Object arg)
6453 { 6777 {
6454 struct Lisp_Symbol *ptr = XSYMBOL (obj); 6778 struct Lisp_Symbol *ptr = XSYMBOL (obj);
6455 nextsym: 6779 nextsym:
6456 if (ptr->u.s.gcmarkbit) 6780 if (symbol_marked_p (ptr))
6457 break; 6781 break;
6458 CHECK_ALLOCATED_AND_LIVE_SYMBOL (); 6782 CHECK_ALLOCATED_AND_LIVE_SYMBOL ();
6459 ptr->u.s.gcmarkbit = 1; 6783 set_symbol_marked(ptr);
6460 /* Attempt to catch bogus objects. */ 6784 /* Attempt to catch bogus objects. */
6461 eassert (valid_lisp_object_p (ptr->u.s.function)); 6785 eassert (valid_lisp_object_p (ptr->u.s.function));
6462 mark_object (ptr->u.s.function); 6786 mark_object (ptr->u.s.function);
@@ -6483,8 +6807,8 @@ mark_object (Lisp_Object arg)
6483 default: emacs_abort (); 6807 default: emacs_abort ();
6484 } 6808 }
6485 if (!PURE_P (XSTRING (ptr->u.s.name))) 6809 if (!PURE_P (XSTRING (ptr->u.s.name)))
6486 MARK_STRING (XSTRING (ptr->u.s.name)); 6810 set_string_marked (XSTRING (ptr->u.s.name));
6487 MARK_INTERVAL_TREE (string_intervals (ptr->u.s.name)); 6811 mark_interval_tree (string_intervals (ptr->u.s.name));
6488 /* Inner loop to mark next symbol in this bucket, if any. */ 6812 /* Inner loop to mark next symbol in this bucket, if any. */
6489 po = ptr = ptr->u.s.next; 6813 po = ptr = ptr->u.s.next;
6490 if (ptr) 6814 if (ptr)
@@ -6495,10 +6819,10 @@ mark_object (Lisp_Object arg)
6495 case Lisp_Cons: 6819 case Lisp_Cons:
6496 { 6820 {
6497 struct Lisp_Cons *ptr = XCONS (obj); 6821 struct Lisp_Cons *ptr = XCONS (obj);
6498 if (CONS_MARKED_P (ptr)) 6822 if (cons_marked_p (ptr))
6499 break; 6823 break;
6500 CHECK_ALLOCATED_AND_LIVE (live_cons_p); 6824 CHECK_ALLOCATED_AND_LIVE (live_cons_p);
6501 CONS_MARK (ptr); 6825 set_cons_marked (ptr);
6502 /* If the cdr is nil, avoid recursion for the car. */ 6826 /* If the cdr is nil, avoid recursion for the car. */
6503 if (NILP (ptr->u.s.u.cdr)) 6827 if (NILP (ptr->u.s.u.cdr))
6504 { 6828 {
@@ -6516,7 +6840,12 @@ mark_object (Lisp_Object arg)
6516 6840
6517 case Lisp_Float: 6841 case Lisp_Float:
6518 CHECK_ALLOCATED_AND_LIVE (live_float_p); 6842 CHECK_ALLOCATED_AND_LIVE (live_float_p);
6519 FLOAT_MARK (XFLOAT (obj)); 6843 /* Do not mark floats stored in a dump image: these floats are
6844 "cold" and do not have mark bits. */
6845 if (pdumper_object_p (XFLOAT (obj)))
6846 eassert (pdumper_cold_object_p (XFLOAT (obj)));
6847 else if (!XFLOAT_MARKED_P (XFLOAT (obj)))
6848 XFLOAT_MARK (XFLOAT (obj));
6520 break; 6849 break;
6521 6850
6522 case_Lisp_Int: 6851 case_Lisp_Int:
@@ -6530,6 +6859,7 @@ mark_object (Lisp_Object arg)
6530#undef CHECK_ALLOCATED 6859#undef CHECK_ALLOCATED
6531#undef CHECK_ALLOCATED_AND_LIVE 6860#undef CHECK_ALLOCATED_AND_LIVE
6532} 6861}
6862
6533/* Mark the Lisp pointers in the terminal objects. 6863/* Mark the Lisp pointers in the terminal objects.
6534 Called by Fgarbage_collect. */ 6864 Called by Fgarbage_collect. */
6535 6865
@@ -6546,13 +6876,11 @@ mark_terminals (void)
6546 gets marked. */ 6876 gets marked. */
6547 mark_image_cache (t->image_cache); 6877 mark_image_cache (t->image_cache);
6548#endif /* HAVE_WINDOW_SYSTEM */ 6878#endif /* HAVE_WINDOW_SYSTEM */
6549 if (!VECTOR_MARKED_P (t)) 6879 if (!vectorlike_marked_p (&t->header))
6550 mark_vectorlike ((struct Lisp_Vector *)t); 6880 mark_vectorlike (&t->header);
6551 } 6881 }
6552} 6882}
6553 6883
6554
6555
6556/* Value is non-zero if OBJ will survive the current GC because it's 6884/* Value is non-zero if OBJ will survive the current GC because it's
6557 either marked or does not need to be marked to survive. */ 6885 either marked or does not need to be marked to survive. */
6558 6886
@@ -6564,27 +6892,29 @@ survives_gc_p (Lisp_Object obj)
6564 switch (XTYPE (obj)) 6892 switch (XTYPE (obj))
6565 { 6893 {
6566 case_Lisp_Int: 6894 case_Lisp_Int:
6567 survives_p = 1; 6895 survives_p = true;
6568 break; 6896 break;
6569 6897
6570 case Lisp_Symbol: 6898 case Lisp_Symbol:
6571 survives_p = XSYMBOL (obj)->u.s.gcmarkbit; 6899 survives_p = symbol_marked_p (XSYMBOL (obj));
6572 break; 6900 break;
6573 6901
6574 case Lisp_String: 6902 case Lisp_String:
6575 survives_p = STRING_MARKED_P (XSTRING (obj)); 6903 survives_p = string_marked_p (XSTRING (obj));
6576 break; 6904 break;
6577 6905
6578 case Lisp_Vectorlike: 6906 case Lisp_Vectorlike:
6579 survives_p = SUBRP (obj) || VECTOR_MARKED_P (XVECTOR (obj)); 6907 survives_p = SUBRP (obj) || vector_marked_p (XVECTOR (obj));
6580 break; 6908 break;
6581 6909
6582 case Lisp_Cons: 6910 case Lisp_Cons:
6583 survives_p = CONS_MARKED_P (XCONS (obj)); 6911 survives_p = cons_marked_p (XCONS (obj));
6584 break; 6912 break;
6585 6913
6586 case Lisp_Float: 6914 case Lisp_Float:
6587 survives_p = FLOAT_MARKED_P (XFLOAT (obj)); 6915 survives_p =
6916 XFLOAT_MARKED_P (XFLOAT (obj)) ||
6917 pdumper_object_p (XFLOAT (obj));
6588 break; 6918 break;
6589 6919
6590 default: 6920 default:
@@ -6638,7 +6968,7 @@ sweep_conses (void)
6638 { 6968 {
6639 struct Lisp_Cons *acons 6969 struct Lisp_Cons *acons
6640 = ptr_bounds_copy (&cblk->conses[pos], cblk); 6970 = ptr_bounds_copy (&cblk->conses[pos], cblk);
6641 if (!CONS_MARKED_P (acons)) 6971 if (!XCONS_MARKED_P (acons))
6642 { 6972 {
6643 this_free++; 6973 this_free++;
6644 cblk->conses[pos].u.s.u.chain = cons_free_list; 6974 cblk->conses[pos].u.s.u.chain = cons_free_list;
@@ -6648,7 +6978,7 @@ sweep_conses (void)
6648 else 6978 else
6649 { 6979 {
6650 num_used++; 6980 num_used++;
6651 CONS_UNMARK (acons); 6981 XUNMARK_CONS (acons);
6652 } 6982 }
6653 } 6983 }
6654 } 6984 }
@@ -6691,7 +7021,7 @@ sweep_floats (void)
6691 for (int i = 0; i < lim; i++) 7021 for (int i = 0; i < lim; i++)
6692 { 7022 {
6693 struct Lisp_Float *afloat = ptr_bounds_copy (&fblk->floats[i], fblk); 7023 struct Lisp_Float *afloat = ptr_bounds_copy (&fblk->floats[i], fblk);
6694 if (!FLOAT_MARKED_P (afloat)) 7024 if (!XFLOAT_MARKED_P (afloat))
6695 { 7025 {
6696 this_free++; 7026 this_free++;
6697 fblk->floats[i].u.chain = float_free_list; 7027 fblk->floats[i].u.chain = float_free_list;
@@ -6700,7 +7030,7 @@ sweep_floats (void)
6700 else 7030 else
6701 { 7031 {
6702 num_used++; 7032 num_used++;
6703 FLOAT_UNMARK (afloat); 7033 XFLOAT_UNMARK (afloat);
6704 } 7034 }
6705 } 7035 }
6706 lim = FLOAT_BLOCK_SIZE; 7036 lim = FLOAT_BLOCK_SIZE;
@@ -6850,7 +7180,7 @@ unchain_dead_markers (struct buffer *buffer)
6850 struct Lisp_Marker *this, **prev = &BUF_MARKERS (buffer); 7180 struct Lisp_Marker *this, **prev = &BUF_MARKERS (buffer);
6851 7181
6852 while ((this = *prev)) 7182 while ((this = *prev))
6853 if (VECTOR_MARKED_P (this)) 7183 if (vectorlike_marked_p (&this->header))
6854 prev = &this->next; 7184 prev = &this->next;
6855 else 7185 else
6856 { 7186 {
@@ -6867,14 +7197,15 @@ sweep_buffers (void)
6867 7197
6868 total_buffers = 0; 7198 total_buffers = 0;
6869 for (buffer = all_buffers; buffer; buffer = *bprev) 7199 for (buffer = all_buffers; buffer; buffer = *bprev)
6870 if (!VECTOR_MARKED_P (buffer)) 7200 if (!vectorlike_marked_p (&buffer->header))
6871 { 7201 {
6872 *bprev = buffer->next; 7202 *bprev = buffer->next;
6873 lisp_free (buffer); 7203 lisp_free (buffer);
6874 } 7204 }
6875 else 7205 else
6876 { 7206 {
6877 VECTOR_UNMARK (buffer); 7207 if (!pdumper_object_p (buffer))
7208 XUNMARK_VECTOR (buffer);
6878 /* Do not use buffer_(set|get)_intervals here. */ 7209 /* Do not use buffer_(set|get)_intervals here. */
6879 buffer->text->intervals = balance_intervals (buffer->text->intervals); 7210 buffer->text->intervals = balance_intervals (buffer->text->intervals);
6880 unchain_dead_markers (buffer); 7211 unchain_dead_markers (buffer);
@@ -6887,10 +7218,6 @@ sweep_buffers (void)
6887static void 7218static void
6888gc_sweep (void) 7219gc_sweep (void)
6889{ 7220{
6890 /* Remove or mark entries in weak hash tables.
6891 This must be done before any object is unmarked. */
6892 sweep_weak_hash_tables ();
6893
6894 sweep_strings (); 7221 sweep_strings ();
6895 check_string_bytes (!noninteractive); 7222 check_string_bytes (!noninteractive);
6896 sweep_conses (); 7223 sweep_conses ();
@@ -6899,6 +7226,7 @@ gc_sweep (void)
6899 sweep_symbols (); 7226 sweep_symbols ();
6900 sweep_buffers (); 7227 sweep_buffers ();
6901 sweep_vectors (); 7228 sweep_vectors ();
7229 pdumper_clear_marks ();
6902 check_string_bytes (!noninteractive); 7230 check_string_bytes (!noninteractive);
6903} 7231}
6904 7232
@@ -7151,19 +7479,34 @@ verify_alloca (void)
7151 7479
7152/* Initialization. */ 7480/* Initialization. */
7153 7481
7482static void init_alloc_once_for_pdumper (void);
7483
7154void 7484void
7155init_alloc_once (void) 7485init_alloc_once (void)
7156{ 7486{
7487 gc_cons_threshold = GC_DEFAULT_THRESHOLD;
7157 /* Even though Qt's contents are not set up, its address is known. */ 7488 /* Even though Qt's contents are not set up, its address is known. */
7158 Vpurify_flag = Qt; 7489 Vpurify_flag = Qt;
7159 7490
7160 purebeg = PUREBEG; 7491 PDUMPER_REMEMBER_SCALAR (buffer_defaults.header);
7161 pure_size = PURESIZE; 7492 PDUMPER_REMEMBER_SCALAR (buffer_local_symbols.header);
7493
7494 /* Call init_alloc_once_for_pdumper now so we run mem_init early.
7495 Keep in mind that when we reload from a dump, we'll run _only_
7496 init_alloc_once_for_pdumper and not init_alloc_once at all. */
7497 pdumper_do_now_and_after_load (init_alloc_once_for_pdumper);
7162 7498
7163 verify_alloca (); 7499 verify_alloca ();
7164 init_finalizer_list (&finalizers);
7165 init_finalizer_list (&doomed_finalizers);
7166 7500
7501 init_strings ();
7502 init_vectors ();
7503}
7504
7505static void
7506init_alloc_once_for_pdumper (void)
7507{
7508 purebeg = PUREBEG;
7509 pure_size = PURESIZE;
7167 mem_init (); 7510 mem_init ();
7168 Vdead = make_pure_string ("DEAD", 4, 4, 0); 7511 Vdead = make_pure_string ("DEAD", 4, 4, 0);
7169 7512
@@ -7172,11 +7515,11 @@ init_alloc_once (void)
7172 mallopt (M_MMAP_THRESHOLD, 64 * 1024); /* Mmap threshold. */ 7515 mallopt (M_MMAP_THRESHOLD, 64 * 1024); /* Mmap threshold. */
7173 mallopt (M_MMAP_MAX, MMAP_MAX_AREAS); /* Max. number of mmap'ed areas. */ 7516 mallopt (M_MMAP_MAX, MMAP_MAX_AREAS); /* Max. number of mmap'ed areas. */
7174#endif 7517#endif
7175 init_strings ();
7176 init_vectors ();
7177 7518
7519
7520 init_finalizer_list (&finalizers);
7521 init_finalizer_list (&doomed_finalizers);
7178 refill_memory_reserve (); 7522 refill_memory_reserve ();
7179 gc_cons_threshold = GC_DEFAULT_THRESHOLD;
7180} 7523}
7181 7524
7182void 7525void
@@ -7184,10 +7527,6 @@ init_alloc (void)
7184{ 7527{
7185 Vgc_elapsed = make_float (0.0); 7528 Vgc_elapsed = make_float (0.0);
7186 gcs_done = 0; 7529 gcs_done = 0;
7187
7188#if USE_VALGRIND
7189 valgrind_p = RUNNING_ON_VALGRIND != 0;
7190#endif
7191} 7530}
7192 7531
7193void 7532void
diff --git a/src/atimer.c b/src/atimer.c
index 4d97470a28f..d36c4f1f5a3 100644
--- a/src/atimer.c
+++ b/src/atimer.c
@@ -584,6 +584,7 @@ init_atimer (void)
584 sigaction (SIGALRM, &action, 0); 584 sigaction (SIGALRM, &action, 0);
585 585
586#ifdef ENABLE_CHECKING 586#ifdef ENABLE_CHECKING
587 defsubr (&Sdebug_timer_check); 587 if (!initialized)
588 defsubr (&Sdebug_timer_check);
588#endif 589#endif
589} 590}
diff --git a/src/buffer.c b/src/buffer.c
index cc0899676de..a12c80ec0b0 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -44,6 +44,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
44#include "keymap.h" 44#include "keymap.h"
45#include "frame.h" 45#include "frame.h"
46#include "xwidget.h" 46#include "xwidget.h"
47#include "pdumper.h"
47 48
48#ifdef WINDOWSNT 49#ifdef WINDOWSNT
49#include "w32heap.h" /* for mmap_* */ 50#include "w32heap.h" /* for mmap_* */
@@ -529,6 +530,8 @@ even if it is dead. The return value is never nil. */)
529 /* No one shows us now. */ 530 /* No one shows us now. */
530 b->window_count = 0; 531 b->window_count = 0;
531 532
533 memset (&b->local_flags, 0, sizeof (b->local_flags));
534
532 BUF_GAP_SIZE (b) = 20; 535 BUF_GAP_SIZE (b) = 20;
533 block_input (); 536 block_input ();
534 /* We allocate extra 1-byte at the tail and keep it always '\0' for 537 /* We allocate extra 1-byte at the tail and keep it always '\0' for
@@ -781,6 +784,8 @@ CLONE nil means the indirect buffer's state is reset to default values. */)
781 /* Always -1 for an indirect buffer. */ 784 /* Always -1 for an indirect buffer. */
782 b->window_count = -1; 785 b->window_count = -1;
783 786
787 memset (&b->local_flags, 0, sizeof (b->local_flags));
788
784 b->pt = b->base_buffer->pt; 789 b->pt = b->base_buffer->pt;
785 b->begv = b->base_buffer->begv; 790 b->begv = b->base_buffer->begv;
786 b->zv = b->base_buffer->zv; 791 b->zv = b->base_buffer->zv;
@@ -5001,24 +5006,37 @@ alloc_buffer_text (struct buffer *b, ptrdiff_t nbytes)
5001void 5006void
5002enlarge_buffer_text (struct buffer *b, ptrdiff_t delta) 5007enlarge_buffer_text (struct buffer *b, ptrdiff_t delta)
5003{ 5008{
5004 void *p;
5005 ptrdiff_t nbytes = (BUF_Z_BYTE (b) - BUF_BEG_BYTE (b) + BUF_GAP_SIZE (b) + 1
5006 + delta);
5007 block_input (); 5009 block_input ();
5010 void *p;
5011 unsigned char *old_beg = b->text->beg;
5012 ptrdiff_t old_nbytes =
5013 BUF_Z_BYTE (b) - BUF_BEG_BYTE (b) + BUF_GAP_SIZE (b) + 1;
5014 ptrdiff_t new_nbytes = old_nbytes + delta;
5015
5016 if (pdumper_object_p (old_beg))
5017 b->text->beg = NULL;
5018 else
5019 old_beg = NULL;
5020
5008#if defined USE_MMAP_FOR_BUFFERS 5021#if defined USE_MMAP_FOR_BUFFERS
5009 p = mmap_realloc ((void **) &b->text->beg, nbytes); 5022 p = mmap_realloc ((void **) &b->text->beg, new_nbytes);
5010#elif defined REL_ALLOC 5023#elif defined REL_ALLOC
5011 p = r_re_alloc ((void **) &b->text->beg, nbytes); 5024 p = r_re_alloc ((void **) &b->text->beg, new_nbytes);
5012#else 5025#else
5013 p = xrealloc (b->text->beg, nbytes); 5026 p = xrealloc (b->text->beg, new_nbytes);
5014#endif 5027#endif
5015 5028
5016 if (p == NULL) 5029 if (p == NULL)
5017 { 5030 {
5031 if (old_beg)
5032 b->text->beg = old_beg;
5018 unblock_input (); 5033 unblock_input ();
5019 memory_full (nbytes); 5034 memory_full (new_nbytes);
5020 } 5035 }
5021 5036
5037 if (old_beg)
5038 memcpy (p, old_beg, min (old_nbytes, new_nbytes));
5039
5022 BUF_BEG_ADDR (b) = p; 5040 BUF_BEG_ADDR (b) = p;
5023 unblock_input (); 5041 unblock_input ();
5024} 5042}
@@ -5031,13 +5049,16 @@ free_buffer_text (struct buffer *b)
5031{ 5049{
5032 block_input (); 5050 block_input ();
5033 5051
5052 if (!pdumper_object_p (b->text->beg))
5053 {
5034#if defined USE_MMAP_FOR_BUFFERS 5054#if defined USE_MMAP_FOR_BUFFERS
5035 mmap_free ((void **) &b->text->beg); 5055 mmap_free ((void **) &b->text->beg);
5036#elif defined REL_ALLOC 5056#elif defined REL_ALLOC
5037 r_alloc_free ((void **) &b->text->beg); 5057 r_alloc_free ((void **) &b->text->beg);
5038#else 5058#else
5039 xfree (b->text->beg); 5059 xfree (b->text->beg);
5040#endif 5060#endif
5061 }
5041 5062
5042 BUF_BEG_ADDR (b) = NULL; 5063 BUF_BEG_ADDR (b) = NULL;
5043 unblock_input (); 5064 unblock_input ();
@@ -5048,14 +5069,25 @@ free_buffer_text (struct buffer *b)
5048/*********************************************************************** 5069/***********************************************************************
5049 Initialization 5070 Initialization
5050 ***********************************************************************/ 5071 ***********************************************************************/
5051
5052void 5072void
5053init_buffer_once (void) 5073init_buffer_once (void)
5054{ 5074{
5075 /* TODO: clean up the buffer-local machinery. Right now,
5076 we have:
5077
5078 buffer_defaults: default values of buffer-locals
5079 buffer_local_flags: metadata
5080 buffer_permanent_local_flags: metadata
5081 buffer_local_symbols: metadata
5082
5083 There must be a simpler way to store the metadata.
5084 */
5085
5055 int idx; 5086 int idx;
5056 5087
5057 /* Items flagged permanent get an explicit permanent-local property 5088 /* Items flagged permanent get an explicit permanent-local property
5058 added in bindings.el, for clarity. */ 5089 added in bindings.el, for clarity. */
5090 PDUMPER_REMEMBER_SCALAR (buffer_permanent_local_flags);
5059 memset (buffer_permanent_local_flags, 0, sizeof buffer_permanent_local_flags); 5091 memset (buffer_permanent_local_flags, 0, sizeof buffer_permanent_local_flags);
5060 5092
5061 /* 0 means not a lisp var, -1 means always local, else mask. */ 5093 /* 0 means not a lisp var, -1 means always local, else mask. */
@@ -5144,10 +5176,15 @@ init_buffer_once (void)
5144 XSETFASTINT (BVAR (&buffer_local_flags, extra_line_spacing), idx); ++idx; 5176 XSETFASTINT (BVAR (&buffer_local_flags, extra_line_spacing), idx); ++idx;
5145 XSETFASTINT (BVAR (&buffer_local_flags, cursor_in_non_selected_windows), idx); ++idx; 5177 XSETFASTINT (BVAR (&buffer_local_flags, cursor_in_non_selected_windows), idx); ++idx;
5146 5178
5179 /* buffer_local_flags contains no pointers, so it's safe to treat it
5180 as a blob for pdumper. */
5181 PDUMPER_REMEMBER_SCALAR (buffer_local_flags);
5182
5147 /* Need more room? */ 5183 /* Need more room? */
5148 if (idx >= MAX_PER_BUFFER_VARS) 5184 if (idx >= MAX_PER_BUFFER_VARS)
5149 emacs_abort (); 5185 emacs_abort ();
5150 last_per_buffer_idx = idx; 5186 last_per_buffer_idx = idx;
5187 PDUMPER_REMEMBER_SCALAR (last_per_buffer_idx);
5151 5188
5152 /* Make sure all markable slots in buffer_defaults 5189 /* Make sure all markable slots in buffer_defaults
5153 are initialized reasonably, so mark_buffer won't choke. */ 5190 are initialized reasonably, so mark_buffer won't choke. */
@@ -5242,7 +5279,9 @@ init_buffer_once (void)
5242 5279
5243 Vbuffer_alist = Qnil; 5280 Vbuffer_alist = Qnil;
5244 current_buffer = 0; 5281 current_buffer = 0;
5282 pdumper_remember_lv_ptr_raw (&current_buffer, Lisp_Vectorlike);
5245 all_buffers = 0; 5283 all_buffers = 0;
5284 pdumper_remember_lv_ptr_raw (&all_buffers, Lisp_Vectorlike);
5246 5285
5247 QSFundamental = build_pure_c_string ("Fundamental"); 5286 QSFundamental = build_pure_c_string ("Fundamental");
5248 5287
@@ -5266,12 +5305,12 @@ init_buffer_once (void)
5266} 5305}
5267 5306
5268void 5307void
5269init_buffer (int initialized) 5308init_buffer (void)
5270{ 5309{
5271 Lisp_Object temp; 5310 Lisp_Object temp;
5272 5311
5273#ifdef USE_MMAP_FOR_BUFFERS 5312#ifdef USE_MMAP_FOR_BUFFERS
5274 if (initialized) 5313 if (dumped_with_unexec_p ())
5275 { 5314 {
5276 struct buffer *b; 5315 struct buffer *b;
5277 5316
@@ -5312,9 +5351,6 @@ init_buffer (int initialized)
5312 eassert (b->text->beg != NULL); 5351 eassert (b->text->beg != NULL);
5313 } 5352 }
5314 } 5353 }
5315#else /* not USE_MMAP_FOR_BUFFERS */
5316 /* Avoid compiler warnings. */
5317 (void) initialized;
5318#endif /* USE_MMAP_FOR_BUFFERS */ 5354#endif /* USE_MMAP_FOR_BUFFERS */
5319 5355
5320 AUTO_STRING (scratch, "*scratch*"); 5356 AUTO_STRING (scratch, "*scratch*");
diff --git a/src/bytecode.c b/src/bytecode.c
index bb7d796bac5..40977799bfc 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -1398,10 +1398,11 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
1398 search as the jump table. */ 1398 search as the jump table. */
1399 Lisp_Object jmp_table = POP; 1399 Lisp_Object jmp_table = POP;
1400 if (BYTE_CODE_SAFE && !HASH_TABLE_P (jmp_table)) 1400 if (BYTE_CODE_SAFE && !HASH_TABLE_P (jmp_table))
1401 emacs_abort (); 1401 emacs_abort ();
1402 Lisp_Object v1 = POP; 1402 Lisp_Object v1 = POP;
1403 ptrdiff_t i; 1403 ptrdiff_t i;
1404 struct Lisp_Hash_Table *h = XHASH_TABLE (jmp_table); 1404 struct Lisp_Hash_Table *h = XHASH_TABLE (jmp_table);
1405 hash_rehash_if_needed (h);
1405 1406
1406 /* h->count is a faster approximation for HASH_TABLE_SIZE (h) 1407 /* h->count is a faster approximation for HASH_TABLE_SIZE (h)
1407 here. */ 1408 here. */
diff --git a/src/callint.c b/src/callint.c
index 0911c49ae59..ba6e3350a50 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -818,7 +818,8 @@ syms_of_callint (void)
818 intern_c_string ("region-beginning"), 818 intern_c_string ("region-beginning"),
819 intern_c_string ("region-end"), 819 intern_c_string ("region-end"),
820 intern_c_string ("point"), 820 intern_c_string ("point"),
821 intern_c_string ("mark")); 821 intern_c_string ("mark"));
822 staticpro (&preserved_fns);
822 823
823 DEFSYM (Qlist, "list"); 824 DEFSYM (Qlist, "list");
824 DEFSYM (Qlet, "let"); 825 DEFSYM (Qlet, "let");
diff --git a/src/callproc.c b/src/callproc.c
index 19882e60fa3..d4558387cfc 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -1588,9 +1588,7 @@ init_callproc (void)
1588 } 1588 }
1589 } 1589 }
1590 1590
1591#ifndef CANNOT_DUMP 1591 if (!will_dump_p ())
1592 if (initialized)
1593#endif
1594 { 1592 {
1595 tempdir = Fdirectory_file_name (Vexec_directory); 1593 tempdir = Fdirectory_file_name (Vexec_directory);
1596 if (! file_accessible_directory_p (tempdir)) 1594 if (! file_accessible_directory_p (tempdir))
diff --git a/src/category.c b/src/category.c
index c504d2d9921..132fae9d404 100644
--- a/src/category.c
+++ b/src/category.c
@@ -42,15 +42,6 @@ bset_category_table (struct buffer *b, Lisp_Object val)
42 b->category_table_ = val; 42 b->category_table_ = val;
43} 43}
44 44
45/* The version number of the latest category table. Each category
46 table has a unique version number. It is assigned a new number
47 also when it is modified. When a regular expression is compiled
48 into the struct re_pattern_buffer, the version number of the
49 category table (of the current buffer) at that moment is also
50 embedded in the structure.
51
52 For the moment, we are not using this feature. */
53static int category_table_version;
54 45
55/* Category set staff. */ 46/* Category set staff. */
56 47
@@ -512,6 +503,4 @@ See the documentation of the variable `word-combining-categories'. */);
512 defsubr (&Schar_category_set); 503 defsubr (&Schar_category_set);
513 defsubr (&Scategory_set_mnemonics); 504 defsubr (&Scategory_set_mnemonics);
514 defsubr (&Smodify_category_entry); 505 defsubr (&Smodify_category_entry);
515
516 category_table_version = 0;
517} 506}
diff --git a/src/charset.c b/src/charset.c
index 724b35536ed..28f6203a66d 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -39,6 +39,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
39#include "coding.h" 39#include "coding.h"
40#include "buffer.h" 40#include "buffer.h"
41#include "sysstdio.h" 41#include "sysstdio.h"
42#include "pdumper.h"
42 43
43/*** GENERAL NOTES on CODED CHARACTER SETS (CHARSETS) *** 44/*** GENERAL NOTES on CODED CHARACTER SETS (CHARSETS) ***
44 45
@@ -61,9 +62,8 @@ Lisp_Object Vcharset_hash_table;
61 62
62/* Table of struct charset. */ 63/* Table of struct charset. */
63struct charset *charset_table; 64struct charset *charset_table;
64 65ptrdiff_t charset_table_size;
65static ptrdiff_t charset_table_size; 66int charset_table_used;
66static int charset_table_used;
67 67
68/* Special charsets corresponding to symbols. */ 68/* Special charsets corresponding to symbols. */
69int charset_ascii; 69int charset_ascii;
@@ -851,6 +851,8 @@ usage: (define-charset-internal ...) */)
851 bool new_definition_p; 851 bool new_definition_p;
852 int nchars; 852 int nchars;
853 853
854 memset (&charset, 0, sizeof (charset));
855
854 if (nargs != charset_arg_max) 856 if (nargs != charset_arg_max)
855 Fsignal (Qwrong_number_of_arguments, 857 Fsignal (Qwrong_number_of_arguments,
856 Fcons (intern ("define-charset-internal"), 858 Fcons (intern ("define-charset-internal"),
@@ -1142,9 +1144,9 @@ usage: (define-charset-internal ...) */)
1142 struct charset *new_table = 1144 struct charset *new_table =
1143 xpalloc (0, &new_size, 1, 1145 xpalloc (0, &new_size, 1,
1144 min (INT_MAX, MOST_POSITIVE_FIXNUM), 1146 min (INT_MAX, MOST_POSITIVE_FIXNUM),
1145 sizeof *charset_table); 1147 sizeof *charset_table);
1146 memcpy (new_table, charset_table, old_size * sizeof *new_table); 1148 memcpy (new_table, charset_table, old_size * sizeof *new_table);
1147 charset_table = new_table; 1149 charset_table = new_table;
1148 charset_table_size = new_size; 1150 charset_table_size = new_size;
1149 /* FIXME: This leaks memory, as the old charset_table becomes 1151 /* FIXME: This leaks memory, as the old charset_table becomes
1150 unreachable. If the old charset table is charset_table_init 1152 unreachable. If the old charset table is charset_table_init
@@ -2316,15 +2318,26 @@ init_charset_once (void)
2316 for (i = 0; i < ISO_MAX_DIMENSION; i++) 2318 for (i = 0; i < ISO_MAX_DIMENSION; i++)
2317 for (j = 0; j < ISO_MAX_CHARS; j++) 2319 for (j = 0; j < ISO_MAX_CHARS; j++)
2318 for (k = 0; k < ISO_MAX_FINAL; k++) 2320 for (k = 0; k < ISO_MAX_FINAL; k++)
2319 iso_charset_table[i][j][k] = -1; 2321 iso_charset_table[i][j][k] = -1;
2322
2323 PDUMPER_REMEMBER_SCALAR (iso_charset_table);
2320 2324
2321 for (i = 0; i < 256; i++) 2325 for (i = 0; i < 256; i++)
2322 emacs_mule_charset[i] = -1; 2326 emacs_mule_charset[i] = -1;
2323 2327
2328 PDUMPER_REMEMBER_SCALAR (emacs_mule_charset);
2329
2324 charset_jisx0201_roman = -1; 2330 charset_jisx0201_roman = -1;
2331 PDUMPER_REMEMBER_SCALAR (charset_jisx0201_roman);
2332
2325 charset_jisx0208_1978 = -1; 2333 charset_jisx0208_1978 = -1;
2334 PDUMPER_REMEMBER_SCALAR (charset_jisx0208_1978);
2335
2326 charset_jisx0208 = -1; 2336 charset_jisx0208 = -1;
2337 PDUMPER_REMEMBER_SCALAR (charset_jisx0208);
2338
2327 charset_ksc5601 = -1; 2339 charset_ksc5601 = -1;
2340 PDUMPER_REMEMBER_SCALAR (charset_ksc5601);
2328} 2341}
2329 2342
2330/* Allocate an initial charset table that is large enough to handle 2343/* Allocate an initial charset table that is large enough to handle
@@ -2365,7 +2378,9 @@ syms_of_charset (void)
2365 2378
2366 charset_table = charset_table_init; 2379 charset_table = charset_table_init;
2367 charset_table_size = ARRAYELTS (charset_table_init); 2380 charset_table_size = ARRAYELTS (charset_table_init);
2381 PDUMPER_REMEMBER_SCALAR (charset_table_size);
2368 charset_table_used = 0; 2382 charset_table_used = 0;
2383 PDUMPER_REMEMBER_SCALAR (charset_table_used);
2369 2384
2370 defsubr (&Scharsetp); 2385 defsubr (&Scharsetp);
2371 defsubr (&Smap_charset_chars); 2386 defsubr (&Smap_charset_chars);
@@ -2411,19 +2426,30 @@ the value may be a list of mnemonics. */);
2411 2426
2412 charset_ascii 2427 charset_ascii
2413 = define_charset_internal (Qascii, 1, "\x00\x7F\0\0\0\0\0", 2428 = define_charset_internal (Qascii, 1, "\x00\x7F\0\0\0\0\0",
2414 0, 127, 'B', -1, 0, 1, 0, 0); 2429 0, 127, 'B', -1, 0, 1, 0, 0);
2430 PDUMPER_REMEMBER_SCALAR (charset_ascii);
2431
2415 charset_iso_8859_1 2432 charset_iso_8859_1
2416 = define_charset_internal (Qiso_8859_1, 1, "\x00\xFF\0\0\0\0\0", 2433 = define_charset_internal (Qiso_8859_1, 1, "\x00\xFF\0\0\0\0\0",
2417 0, 255, -1, -1, -1, 1, 0, 0); 2434 0, 255, -1, -1, -1, 1, 0, 0);
2435 PDUMPER_REMEMBER_SCALAR (charset_iso_8859_1);
2436
2418 charset_unicode 2437 charset_unicode
2419 = define_charset_internal (Qunicode, 3, "\x00\xFF\x00\xFF\x00\x10\0", 2438 = define_charset_internal (Qunicode, 3, "\x00\xFF\x00\xFF\x00\x10\0",
2420 0, MAX_UNICODE_CHAR, -1, 0, -1, 1, 0, 0); 2439 0, MAX_UNICODE_CHAR, -1, 0, -1, 1, 0, 0);
2440 PDUMPER_REMEMBER_SCALAR (charset_unicode);
2441
2421 charset_emacs 2442 charset_emacs
2422 = define_charset_internal (Qemacs, 3, "\x00\xFF\x00\xFF\x00\x3F\0", 2443 = define_charset_internal (Qemacs, 3, "\x00\xFF\x00\xFF\x00\x3F\0",
2423 0, MAX_5_BYTE_CHAR, -1, 0, -1, 1, 1, 0); 2444 0, MAX_5_BYTE_CHAR, -1, 0, -1, 1, 1, 0);
2445 PDUMPER_REMEMBER_SCALAR (charset_emacs);
2446
2424 charset_eight_bit 2447 charset_eight_bit
2425 = define_charset_internal (Qeight_bit, 1, "\x80\xFF\0\0\0\0\0", 2448 = define_charset_internal (Qeight_bit, 1, "\x80\xFF\0\0\0\0\0",
2426 128, 255, -1, 0, -1, 0, 1, 2449 128, 255, -1, 0, -1, 0, 1,
2427 MAX_5_BYTE_CHAR + 1); 2450 MAX_5_BYTE_CHAR + 1);
2451 PDUMPER_REMEMBER_SCALAR (charset_eight_bit);
2452
2428 charset_unibyte = charset_iso_8859_1; 2453 charset_unibyte = charset_iso_8859_1;
2454 PDUMPER_REMEMBER_SCALAR (charset_unibyte);
2429} 2455}
diff --git a/src/charset.h b/src/charset.h
index 0822f2d12fe..f4bed558cf2 100644
--- a/src/charset.h
+++ b/src/charset.h
@@ -248,6 +248,8 @@ extern Lisp_Object Vcharset_hash_table;
248 248
249/* Table of struct charset. */ 249/* Table of struct charset. */
250extern struct charset *charset_table; 250extern struct charset *charset_table;
251extern ptrdiff_t charset_table_size;
252extern int charset_table_used;
251 253
252#define CHARSET_FROM_ID(id) (charset_table + (id)) 254#define CHARSET_FROM_ID(id) (charset_table + (id))
253 255
diff --git a/src/coding.c b/src/coding.c
index 1c1462198ca..665aefa34c8 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -298,6 +298,7 @@ encode_coding_XXX (struct coding_system *coding)
298#include "composite.h" 298#include "composite.h"
299#include "coding.h" 299#include "coding.h"
300#include "termhooks.h" 300#include "termhooks.h"
301#include "pdumper.h"
301 302
302Lisp_Object Vcoding_system_hash_table; 303Lisp_Object Vcoding_system_hash_table;
303 304
@@ -10737,6 +10738,9 @@ init_coding_once (void)
10737 coding_priorities[i] = i; 10738 coding_priorities[i] = i;
10738 } 10739 }
10739 10740
10741 PDUMPER_REMEMBER_SCALAR (coding_categories);
10742 PDUMPER_REMEMBER_SCALAR (coding_priorities);
10743
10740 /* ISO2022 specific initialize routine. */ 10744 /* ISO2022 specific initialize routine. */
10741 for (i = 0; i < 0x20; i++) 10745 for (i = 0; i < 0x20; i++)
10742 iso_code_class[i] = ISO_control_0; 10746 iso_code_class[i] = ISO_control_0;
@@ -10756,6 +10760,8 @@ init_coding_once (void)
10756 iso_code_class[ISO_CODE_SS3] = ISO_single_shift_3; 10760 iso_code_class[ISO_CODE_SS3] = ISO_single_shift_3;
10757 iso_code_class[ISO_CODE_CSI] = ISO_control_sequence_introducer; 10761 iso_code_class[ISO_CODE_CSI] = ISO_control_sequence_introducer;
10758 10762
10763 PDUMPER_REMEMBER_SCALAR (iso_code_class);
10764
10759 for (i = 0; i < 256; i++) 10765 for (i = 0; i < 256; i++)
10760 { 10766 {
10761 emacs_mule_bytes[i] = 1; 10767 emacs_mule_bytes[i] = 1;
@@ -10764,6 +10770,8 @@ init_coding_once (void)
10764 emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_12] = 3; 10770 emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_12] = 3;
10765 emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_21] = 4; 10771 emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_21] = 4;
10766 emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_22] = 4; 10772 emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_22] = 4;
10773
10774 PDUMPER_REMEMBER_SCALAR (emacs_mule_bytes);
10767} 10775}
10768 10776
10769void 10777void
@@ -10785,6 +10793,7 @@ syms_of_coding (void)
10785 Vcode_conversion_workbuf_name = build_pure_c_string (" *code-conversion-work*"); 10793 Vcode_conversion_workbuf_name = build_pure_c_string (" *code-conversion-work*");
10786 10794
10787 reused_workbuf_in_use = 0; 10795 reused_workbuf_in_use = 0;
10796 PDUMPER_REMEMBER_SCALAR (reused_workbuf_in_use);
10788 10797
10789 DEFSYM (Qcharset, "charset"); 10798 DEFSYM (Qcharset, "charset");
10790 DEFSYM (Qtarget_idx, "target-idx"); 10799 DEFSYM (Qtarget_idx, "target-idx");
diff --git a/src/composite.c b/src/composite.c
index cd8364a2936..c426cbb1246 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -654,6 +654,7 @@ Lisp_Object
654composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len) 654composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len)
655{ 655{
656 struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table); 656 struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
657 hash_rehash_if_needed (h);
657 Lisp_Object header = LGSTRING_HEADER (gstring); 658 Lisp_Object header = LGSTRING_HEADER (gstring);
658 EMACS_UINT hash = h->test.hashfn (&h->test, header); 659 EMACS_UINT hash = h->test.hashfn (&h->test, header);
659 if (len < 0) 660 if (len < 0)
diff --git a/src/conf_post.h b/src/conf_post.h
index 002ef6c65bc..125dbf01528 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -299,8 +299,10 @@ extern int emacs_setenv_TZ (char const *);
299 299
300#if 3 <= __GNUC__ 300#if 3 <= __GNUC__
301# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) 301# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
302# define ATTRIBUTE_SECTION(name) __attribute__((section (name)))
302#else 303#else
303# define ATTRIBUTE_MALLOC 304# define ATTRIBUTE_MALLOC
305#define ATTRIBUTE_SECTION(name)
304#endif 306#endif
305 307
306#if __has_attribute (alloc_size) 308#if __has_attribute (alloc_size)
diff --git a/src/data.c b/src/data.c
index a9908a34f4f..92a1062280e 100644
--- a/src/data.c
+++ b/src/data.c
@@ -804,7 +804,7 @@ The return value is undefined. */)
804 804
805 { 805 {
806 bool autoload = AUTOLOADP (definition); 806 bool autoload = AUTOLOADP (definition);
807 if (NILP (Vpurify_flag) || !autoload) 807 if (!will_dump_p () || !autoload)
808 { /* Only add autoload entries after dumping, because the ones before are 808 { /* Only add autoload entries after dumping, because the ones before are
809 not useful and else we get loads of them from the loaddefs.el. */ 809 not useful and else we get loads of them from the loaddefs.el. */
810 810
@@ -1826,7 +1826,7 @@ The function `default-value' gets the default value and `set-default' sets it.
1826{ 1826{
1827 struct Lisp_Symbol *sym; 1827 struct Lisp_Symbol *sym;
1828 struct Lisp_Buffer_Local_Value *blv = NULL; 1828 struct Lisp_Buffer_Local_Value *blv = NULL;
1829 union Lisp_Val_Fwd valcontents; 1829 union Lisp_Val_Fwd valcontents UNINIT;
1830 bool forwarded UNINIT; 1830 bool forwarded UNINIT;
1831 1831
1832 CHECK_SYMBOL (variable); 1832 CHECK_SYMBOL (variable);
@@ -1893,7 +1893,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */)
1893{ 1893{
1894 Lisp_Object tem; 1894 Lisp_Object tem;
1895 bool forwarded UNINIT; 1895 bool forwarded UNINIT;
1896 union Lisp_Val_Fwd valcontents; 1896 union Lisp_Val_Fwd valcontents UNINIT;
1897 struct Lisp_Symbol *sym; 1897 struct Lisp_Symbol *sym;
1898 struct Lisp_Buffer_Local_Value *blv = NULL; 1898 struct Lisp_Buffer_Local_Value *blv = NULL;
1899 1899
@@ -2958,7 +2958,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args,
2958 /* Set ACCUM to the next operation's result if it fits, 2958 /* Set ACCUM to the next operation's result if it fits,
2959 else exit the loop. */ 2959 else exit the loop. */
2960 bool overflow = false; 2960 bool overflow = false;
2961 intmax_t a; 2961 intmax_t a UNINIT;
2962 switch (code) 2962 switch (code)
2963 { 2963 {
2964 case Aadd : overflow = INT_ADD_WRAPV (accum, next, &a); break; 2964 case Aadd : overflow = INT_ADD_WRAPV (accum, next, &a); break;
diff --git a/src/dbusbind.c b/src/dbusbind.c
index e1c4eda76e9..0afae6b05ad 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -1831,6 +1831,8 @@ be called when the D-Bus reply message arrives. */);
1831 xd_registered_buses = Qnil; 1831 xd_registered_buses = Qnil;
1832 staticpro (&xd_registered_buses); 1832 staticpro (&xd_registered_buses);
1833 1833
1834 // TODO: reset buses on dump load
1835
1834 Fprovide (intern_c_string ("dbusbind"), Qnil); 1836 Fprovide (intern_c_string ("dbusbind"), Qnil);
1835 1837
1836} 1838}
diff --git a/src/dispnew.c b/src/dispnew.c
index 55cdaf5de8a..88783cd5da7 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -42,6 +42,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
42#include "systime.h" 42#include "systime.h"
43#include "tparam.h" 43#include "tparam.h"
44#include "xwidget.h" 44#include "xwidget.h"
45#include "pdumper.h"
45 46
46#ifdef HAVE_WINDOW_SYSTEM 47#ifdef HAVE_WINDOW_SYSTEM
47#include TERM_HEADER 48#include TERM_HEADER
@@ -5987,12 +5988,24 @@ pass nil for VARIABLE. */)
5987 Initialization 5988 Initialization
5988***********************************************************************/ 5989***********************************************************************/
5989 5990
5991static void
5992init_faces_initial (void)
5993{
5994 /* For the initial frame, we don't have any way of knowing what
5995 are the foreground and background colors of the terminal. */
5996 struct frame *sf = SELECTED_FRAME ();
5997
5998 FRAME_FOREGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_FG_COLOR;
5999 FRAME_BACKGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_BG_COLOR;
6000 call0 (intern ("tty-set-up-initial-frame-faces"));
6001}
6002
5990/* Initialization done when Emacs fork is started, before doing stty. 6003/* Initialization done when Emacs fork is started, before doing stty.
5991 Determine terminal type and set terminal_driver. Then invoke its 6004 Determine terminal type and set terminal_driver. Then invoke its
5992 decoding routine to set up variables in the terminal package. */ 6005 decoding routine to set up variables in the terminal package. */
5993 6006
5994void 6007static void
5995init_display (void) 6008init_display_interactive (void)
5996{ 6009{
5997 char *terminal_type; 6010 char *terminal_type;
5998 6011
@@ -6012,9 +6025,7 @@ init_display (void)
6012 with. Otherwise newly opened tty frames will not resize 6025 with. Otherwise newly opened tty frames will not resize
6013 automatically. */ 6026 automatically. */
6014#ifdef SIGWINCH 6027#ifdef SIGWINCH
6015#ifndef CANNOT_DUMP 6028 if (!will_dump_p ())
6016 if (initialized)
6017#endif /* CANNOT_DUMP */
6018 { 6029 {
6019 struct sigaction action; 6030 struct sigaction action;
6020 emacs_sigaction_init (&action, deliver_window_change_signal); 6031 emacs_sigaction_init (&action, deliver_window_change_signal);
@@ -6078,11 +6089,7 @@ init_display (void)
6078#endif /* HAVE_NTGUI */ 6089#endif /* HAVE_NTGUI */
6079 6090
6080#ifdef HAVE_NS 6091#ifdef HAVE_NS
6081 if (!inhibit_window_system 6092 if (!inhibit_window_system && !will_dump_p ())
6082#ifndef CANNOT_DUMP
6083 && initialized
6084#endif
6085 )
6086 { 6093 {
6087 Vinitial_window_system = Qns; 6094 Vinitial_window_system = Qns;
6088 Vwindow_system_version = make_fixnum (10); 6095 Vwindow_system_version = make_fixnum (10);
@@ -6170,22 +6177,23 @@ init_display (void)
6170 6177
6171 calculate_costs (XFRAME (selected_frame)); 6178 calculate_costs (XFRAME (selected_frame));
6172 6179
6173 /* Set up faces of the initial terminal frame of a dumped Emacs. */ 6180 /* Set up faces of the initial terminal frame. */
6174 if (initialized 6181 if (!noninteractive && NILP (Vinitial_window_system))
6175 && !noninteractive 6182 init_faces_initial ();
6176 && NILP (Vinitial_window_system)) 6183}
6177 {
6178 /* For the initial frame, we don't have any way of knowing what
6179 are the foreground and background colors of the terminal. */
6180 struct frame *sf = SELECTED_FRAME ();
6181 6184
6182 FRAME_FOREGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_FG_COLOR; 6185void
6183 FRAME_BACKGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_BG_COLOR; 6186init_display (void)
6184 call0 (intern ("tty-set-up-initial-frame-faces")); 6187{
6188 if (noninteractive)
6189 {
6190 if (dumped_with_pdumper_p ())
6191 init_faces_initial ();
6185 } 6192 }
6193 else
6194 init_display_interactive ();
6186} 6195}
6187 6196
6188
6189 6197
6190/*********************************************************************** 6198/***********************************************************************
6191 Blinking cursor 6199 Blinking cursor
@@ -6220,6 +6228,8 @@ WINDOW nil or omitted means report on the selected window. */)
6220 Initialization 6228 Initialization
6221 ***********************************************************************/ 6229 ***********************************************************************/
6222 6230
6231static void syms_of_display_for_pdumper (void);
6232
6223void 6233void
6224syms_of_display (void) 6234syms_of_display (void)
6225{ 6235{
@@ -6327,11 +6337,12 @@ See `buffer-display-table' for more information. */);
6327 beginning of the next redisplay). */ 6337 beginning of the next redisplay). */
6328 redisplay_dont_pause = true; 6338 redisplay_dont_pause = true;
6329 6339
6330#ifdef CANNOT_DUMP 6340 pdumper_do_now_and_after_load (syms_of_display_for_pdumper);
6331 if (noninteractive) 6341}
6332#endif 6342
6333 { 6343static void
6334 Vinitial_window_system = Qnil; 6344syms_of_display_for_pdumper (void)
6335 Vwindow_system_version = Qnil; 6345{
6336 } 6346 Vinitial_window_system = Qnil;
6347 Vwindow_system_version = Qnil;
6337} 6348}
diff --git a/src/dmpstruct.awk b/src/dmpstruct.awk
new file mode 100755
index 00000000000..d222d117e62
--- /dev/null
+++ b/src/dmpstruct.awk
@@ -0,0 +1,28 @@
1BEGIN {
2 print "/* Generated by dmpstruct.awk */"
3 print "#ifndef EMACS_DMPSTRUCT_H"
4 print "#define EMACS_DMPSTRUCT_H"
5 struct_name = ""
6 tmpfile = "dmpstruct.tmp"
7}
8# Match a type followed by optional syntactic whitespace
9/^(enum|struct|union) [a-zA-Z0-9_]+([\t ]|\/\*.*\*\/)*$/ {
10 struct_name = $2
11 close (tmpfile)
12}
13/^(enum|struct|union) [a-zA-Z0-9_]+([\t ]|\/\*.*\*\/)*$/, /^( )?};$/ {
14 print $0 > tmpfile
15}
16/^( )?} *(GCALIGNED_STRUCT)? *;$/ {
17 if (struct_name != "") {
18 fflush (tmpfile)
19 cmd = "../lib-src/make-fingerprint -r " tmpfile
20 cmd | getline hash
21 close (cmd)
22 printf "#define HASH_%s_%.10s\n", struct_name, hash
23 struct_name = ""
24 }
25}
26END {
27 print "#endif /* EMACS_DMPSTRUCT_H */"
28}
diff --git a/src/doc.c b/src/doc.c
index 04370f7cc62..3e43d6db069 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -118,17 +118,15 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
118 Lisp_Object docdir 118 Lisp_Object docdir
119 = NILP (tem) ? ENCODE_FILE (Vdoc_directory) : empty_unibyte_string; 119 = NILP (tem) ? ENCODE_FILE (Vdoc_directory) : empty_unibyte_string;
120 ptrdiff_t docdir_sizemax = SBYTES (docdir) + 1; 120 ptrdiff_t docdir_sizemax = SBYTES (docdir) + 1;
121#ifndef CANNOT_DUMP 121 if (will_dump_p ())
122 docdir_sizemax = max (docdir_sizemax, sizeof sibling_etc); 122 docdir_sizemax = max (docdir_sizemax, sizeof sibling_etc);
123#endif
124 name = SAFE_ALLOCA (docdir_sizemax + SBYTES (file)); 123 name = SAFE_ALLOCA (docdir_sizemax + SBYTES (file));
125 lispstpcpy (lispstpcpy (name, docdir), file); 124 lispstpcpy (lispstpcpy (name, docdir), file);
126 125
127 fd = emacs_open (name, O_RDONLY, 0); 126 fd = emacs_open (name, O_RDONLY, 0);
128 if (fd < 0) 127 if (fd < 0)
129 { 128 {
130#ifndef CANNOT_DUMP 129 if (will_dump_p ())
131 if (!NILP (Vpurify_flag))
132 { 130 {
133 /* Preparing to dump; DOC file is probably not installed. 131 /* Preparing to dump; DOC file is probably not installed.
134 So check in ../etc. */ 132 So check in ../etc. */
@@ -136,7 +134,6 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
136 134
137 fd = emacs_open (name, O_RDONLY, 0); 135 fd = emacs_open (name, O_RDONLY, 0);
138 } 136 }
139#endif
140 if (fd < 0) 137 if (fd < 0)
141 { 138 {
142 if (errno == EMFILE || errno == ENFILE) 139 if (errno == EMFILE || errno == ENFILE)
@@ -545,12 +542,7 @@ the same file name is found in the `doc-directory'. */)
545 542
546 CHECK_STRING (filename); 543 CHECK_STRING (filename);
547 544
548 if 545 if (will_dump_p ())
549#ifndef CANNOT_DUMP
550 (!NILP (Vpurify_flag))
551#else /* CANNOT_DUMP */
552 (0)
553#endif /* CANNOT_DUMP */
554 { 546 {
555 dirname = sibling_etc; 547 dirname = sibling_etc;
556 dirlen = sizeof sibling_etc - 1; 548 dirlen = sizeof sibling_etc - 1;
diff --git a/src/editfns.c b/src/editfns.c
index 55127011d82..01376b06373 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3454,7 +3454,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
3454 3454
3455 bool format_as_long_double = false; 3455 bool format_as_long_double = false;
3456 double darg; 3456 double darg;
3457 long double ldarg; 3457 long double ldarg UNINIT;
3458 3458
3459 if (FLOATP (arg)) 3459 if (FLOATP (arg))
3460 darg = XFLOAT_DATA (arg); 3460 darg = XFLOAT_DATA (arg);
diff --git a/src/emacs-module.c b/src/emacs-module.c
index e695a3d2e64..cbab0234201 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -1191,7 +1191,10 @@ void
1191syms_of_module (void) 1191syms_of_module (void)
1192{ 1192{
1193 if (!plain_values) 1193 if (!plain_values)
1194 ltv_mark = Fcons (Qnil, Qnil); 1194 {
1195 ltv_mark = Fcons (Qnil, Qnil);
1196 staticpro (&ltv_mark);
1197 }
1195 eassert (NILP (value_to_lisp (module_nil))); 1198 eassert (NILP (value_to_lisp (module_nil)));
1196 1199
1197 DEFSYM (Qmodule_refs_hash, "module-refs-hash"); 1200 DEFSYM (Qmodule_refs_hash, "module-refs-hash");
diff --git a/src/emacs.c b/src/emacs.c
index 221b074afc9..9c88b6e3f17 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -118,6 +118,9 @@ extern char etext;
118#include <sys/resource.h> 118#include <sys/resource.h>
119#endif 119#endif
120 120
121#include "pdumper.h"
122#include "epaths.h"
123
121static const char emacs_version[] = PACKAGE_VERSION; 124static const char emacs_version[] = PACKAGE_VERSION;
122static const char emacs_copyright[] = COPYRIGHT; 125static const char emacs_copyright[] = COPYRIGHT;
123static const char emacs_bugreport[] = PACKAGE_BUGREPORT; 126static const char emacs_bugreport[] = PACKAGE_BUGREPORT;
@@ -130,19 +133,9 @@ Lisp_Object empty_unibyte_string, empty_multibyte_string;
130Lisp_Object Vlibrary_cache; 133Lisp_Object Vlibrary_cache;
131#endif 134#endif
132 135
133/* Set after Emacs has started up the first time. 136struct gflags gflags;
134 Prevents reinitialization of the Lisp world and keymaps
135 on subsequent starts. */
136bool initialized; 137bool initialized;
137 138
138#ifndef CANNOT_DUMP
139/* Set to true if this instance of Emacs might dump. */
140# ifndef DOUG_LEA_MALLOC
141static
142# endif
143bool might_dump;
144#endif
145
146/* If true, Emacs should not attempt to use a window-specific code, 139/* If true, Emacs should not attempt to use a window-specific code,
147 but instead should use the virtual terminal under which it was started. */ 140 but instead should use the virtual terminal under which it was started. */
148bool inhibit_window_system; 141bool inhibit_window_system;
@@ -519,8 +512,7 @@ init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd)
519 etc_exists = Ffile_exists_p (tem); 512 etc_exists = Ffile_exists_p (tem);
520 if (!NILP (etc_exists)) 513 if (!NILP (etc_exists))
521 { 514 {
522 Vinstallation_directory 515 Vinstallation_directory = Ffile_name_as_directory (dir);
523 = Ffile_name_as_directory (dir);
524 break; 516 break;
525 } 517 }
526 } 518 }
@@ -545,8 +537,7 @@ init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd)
545 if (!NILP (etc_exists)) 537 if (!NILP (etc_exists))
546 { 538 {
547 tem = Fexpand_file_name (build_string (".."), dir); 539 tem = Fexpand_file_name (build_string (".."), dir);
548 Vinstallation_directory 540 Vinstallation_directory = Ffile_name_as_directory (tem);
549 = Ffile_name_as_directory (tem);
550 break; 541 break;
551 } 542 }
552 } 543 }
@@ -659,6 +650,43 @@ argmatch (char **argv, int argc, const char *sstr, const char *lstr,
659 } 650 }
660} 651}
661 652
653static bool
654string_starts_with_p (const char* string, const char* prefix)
655{
656 return strncmp (string, prefix, strlen (prefix)) == 0;
657}
658
659/* Return the value of GNU-style long argument ARGUMENT if given on
660 command line. ARGUMENT must begin with "-". If ARGUMENT is not
661 given, return NULL. */
662static char *
663find_argument (const char *argument, int argc, char **argv)
664{
665 char *found = NULL;
666 int i;
667
668 eassert (argument[0] == '-');
669
670 for (i = 1; i < argc; ++i)
671 if (string_starts_with_p (argv[i], argument) &&
672 ((argv[i] + strlen (argument))[0] == '=' ||
673 (argv[i] + strlen (argument))[0] == '\0'))
674 {
675 int j = i;
676 found = argv[j++] + strlen (argument);
677 if (*found == '=')
678 ++found;
679 else if (i < argc)
680 found = argv[j++];
681 else
682 fatal ("no argument given for %s", argument);
683 break;
684 }
685 else if (strcmp (argv[i], "--") == 0)
686 break;
687 return found;
688}
689
662/* Close standard output and standard error, reporting any write 690/* Close standard output and standard error, reporting any write
663 errors as best we can. This is intended for use with atexit. */ 691 errors as best we can. This is intended for use with atexit. */
664static void 692static void
@@ -677,6 +705,114 @@ close_output_streams (void)
677 _exit (EXIT_FAILURE); 705 _exit (EXIT_FAILURE);
678} 706}
679 707
708#ifdef HAVE_PDUMPER
709
710static const char *
711dump_error_to_string (enum pdumper_load_result result)
712{
713 switch (result)
714 {
715 case PDUMPER_LOAD_SUCCESS:
716 return "success";
717 case PDUMPER_LOAD_OOM:
718 return "out of memory";
719 case PDUMPER_NOT_LOADED:
720 return "not loaded";
721 case PDUMPER_LOAD_FILE_NOT_FOUND:
722 return "could not open file";
723 case PDUMPER_LOAD_BAD_FILE_TYPE:
724 return "not a dump file";
725 case PDUMPER_LOAD_FAILED_DUMP:
726 return "dump file is result of failed dump attempt";
727 case PDUMPER_LOAD_VERSION_MISMATCH:
728 return "not built for this Emacs executable";
729 default:
730 return "generic error";
731 }
732}
733
734#define PDUMP_FILE_ARG "--dump-file"
735
736static enum pdumper_load_result
737load_pdump (int argc, char **argv)
738{
739 const char *const suffix = ".pdmp";
740 const char *const argv0_base = "emacs";
741 enum pdumper_load_result result;
742#ifdef WINDOWSNT
743 size_t argv0_len;
744#endif
745
746 /* TODO: maybe more thoroughly scrub process environment in order to
747 make this use case (loading a pdumper image in an unexeced emacs)
748 possible? Right now, we assume that things we don't touch are
749 zero-initialized, and in an unexeced Emacs, this assumption
750 doesn't hold. */
751 if (initialized)
752 fatal ("cannot load pdumper image in unexeced Emacs");
753
754 /* Look for an explicitly-specified dump file. */
755 const char *path_exec = PATH_EXEC;
756 char *dump_file = find_argument (PDUMP_FILE_ARG, argc, argv);
757
758 result = PDUMPER_NOT_LOADED;
759 if (dump_file)
760 result = pdumper_load (dump_file);
761
762 if (dump_file && result != PDUMPER_LOAD_SUCCESS)
763 fatal ("could not load dump file \"%s\": %s",
764 dump_file, dump_error_to_string (result));
765
766 if (result == PDUMPER_LOAD_SUCCESS)
767 goto out;
768
769 /* Look for a dump file in the same directory as the executable; it
770 should have the same basename. */
771
772 dump_file = alloca (strlen (argv[0]) + strlen (suffix) + 1);
773#ifdef WINDOWSNT
774 /* Remove the .exe extension if present. */
775 argv0_len = strlen (argv[0]);
776 if (argv0_len >= 4 && c_strcasecmp (argv[0] + argv0_len - 4, ".exe") == 0)
777 sprintf (dump_file, "%.*s%s", argv0_len - 4, argv[0], suffix);
778 else
779#endif
780 sprintf (dump_file, "%s%s", argv[0], suffix);
781
782 result = pdumper_load (dump_file);
783 if (result == PDUMPER_LOAD_SUCCESS)
784 goto out;
785
786 if (result != PDUMPER_LOAD_FILE_NOT_FOUND)
787 fatal ("could not load dump file \"%s\": %s",
788 dump_file, dump_error_to_string (result));
789
790 /* Finally, look for "emacs.pdmp" in PATH_EXEC. We hardcode
791 "emacs" in "emacs.pdmp" so that the Emacs binary still works
792 if the user copies and renames it.
793
794 FIXME: this doesn't work with emacs-XX.YY.ZZ.pdmp versioned files. */
795#ifdef WINDOWSNT
796 /* On MS-Windows, PATH_EXEC normally starts with a literal
797 "%emacs_dir%", so it will never work without some tweaking. */
798 path_exec = w32_relocate (path_exec);
799#endif
800 dump_file = alloca (strlen (path_exec)
801 + 1
802 + strlen (argv0_base)
803 + strlen (suffix)
804 + 1);
805 sprintf (dump_file, "%s%c%s%s",
806 path_exec, DIRECTORY_SEP, argv0_base, suffix);
807 result = pdumper_load (dump_file);
808 if (result != PDUMPER_LOAD_SUCCESS)
809 dump_file = NULL;
810
811 out:
812 return result;
813}
814#endif /* HAVE_PDUMPER */
815
680/* ARGSUSED */ 816/* ARGSUSED */
681int 817int
682main (int argc, char **argv) 818main (int argc, char **argv)
@@ -686,7 +822,6 @@ main (int argc, char **argv)
686 void *stack_bottom_variable; 822 void *stack_bottom_variable;
687 823
688 bool do_initial_setlocale; 824 bool do_initial_setlocale;
689 bool dumping;
690 int skip_args = 0; 825 int skip_args = 0;
691 bool no_loadup = false; 826 bool no_loadup = false;
692 char *junk = 0; 827 char *junk = 0;
@@ -702,25 +837,62 @@ main (int argc, char **argv)
702 /* Record (approximately) where the stack begins. */ 837 /* Record (approximately) where the stack begins. */
703 stack_bottom = (char *) &stack_bottom_variable; 838 stack_bottom = (char *) &stack_bottom_variable;
704 839
705#ifndef CANNOT_DUMP 840 const char *dump_mode = NULL;
706 dumping = !initialized && (strcmp (argv[argc - 1], "dump") == 0 841 const char *temacs = find_argument ("--temacs", argc, argv);
707 || strcmp (argv[argc - 1], "bootstrap") == 0); 842#ifdef HAVE_PDUMPER
708#else 843 bool attempt_load_pdump = false;
709 dumping = false;
710#endif 844#endif
711 845
712 argc = maybe_disable_address_randomization (dumping, argc, argv); 846 /* Look for this argument first, before any heap allocation, so we
713 847 can set heap flags properly if we're going to unexec. */
848 if (!initialized && temacs)
849 {
714#ifndef CANNOT_DUMP 850#ifndef CANNOT_DUMP
715 might_dump = !initialized; 851 if (strcmp (temacs, "dump") == 0 ||
716 852 strcmp (temacs, "bootstrap") == 0)
717# ifdef GNU_LINUX 853 gflags.will_dump_with_unexec_ = true;
718 if (!initialized) 854#endif
855#ifdef HAVE_PDUMPER
856 if (strcmp (temacs, "pdump") == 0 ||
857 strcmp (temacs, "pbootstrap") == 0)
858 gflags.will_dump_with_pdumper_ = true;
859#endif
860#if defined (HAVE_PDUMPER) || !defined (CANNOT_DUMP)
861 if (strcmp (temacs, "bootstrap") == 0 ||
862 strcmp (temacs, "pbootstrap") == 0)
863 gflags.will_bootstrap_ = true;
864 gflags.will_dump_ =
865 will_dump_with_pdumper_p () ||
866 will_dump_with_unexec_p ();
867 if (will_dump_p ())
868 dump_mode = temacs;
869#endif
870 if (!dump_mode)
871 fatal ("Invalid temacs mode '%s'", temacs);
872 }
873 else if (temacs)
719 { 874 {
720 char *heap_start = my_heap_start (); 875 fatal ("--temacs not supported for unexeced emacs");
721 heap_bss_diff = heap_start - max (my_endbss, my_endbss_static);
722 } 876 }
723# endif 877 else if (initialized)
878 {
879#ifdef HAVE_PDUMPER
880 if (find_argument (PDUMP_FILE_ARG, argc, argv))
881 fatal ("%s not supported in unexeced emacs", PDUMP_FILE_ARG);
882#endif
883 }
884 else
885 {
886 eassert (!initialized);
887 eassert (!temacs);
888#ifdef PDUMP_FILE_ARG
889 attempt_load_pdump = true;
890#endif
891 }
892
893#ifndef CANNOT_DUMP
894 if (!will_dump_with_unexec_p ())
895 gflags.will_not_unexec_ = true;
724#endif 896#endif
725 897
726#if defined WINDOWSNT || defined HAVE_NTGUI 898#if defined WINDOWSNT || defined HAVE_NTGUI
@@ -742,6 +914,22 @@ main (int argc, char **argv)
742 w32_init_main_thread (); 914 w32_init_main_thread ();
743#endif 915#endif
744 916
917#ifdef HAVE_PDUMPER
918 if (attempt_load_pdump)
919 load_pdump (argc, argv);
920#endif
921
922 argc = maybe_disable_address_randomization (
923 will_dump_with_unexec_p (), argc, argv);
924
925#if defined (GNU_LINUX) && !defined (CANNOT_DUMP)
926 if (!initialized)
927 {
928 char *heap_start = my_heap_start ();
929 heap_bss_diff = heap_start - max (my_endbss, my_endbss_static);
930 }
931#endif
932
745#ifdef RUN_TIME_REMAP 933#ifdef RUN_TIME_REMAP
746 if (initialized) 934 if (initialized)
747 run_time_remap (argv[0]); 935 run_time_remap (argv[0]);
@@ -850,10 +1038,7 @@ main (int argc, char **argv)
850 frames. */ 1038 frames. */
851 int extra = (30 * 1000) * 50; 1039 int extra = (30 * 1000) * 50;
852 1040
853 bool try_to_grow_stack = true; 1041 bool try_to_grow_stack = !noninteractive || initialized;
854#ifndef CANNOT_DUMP
855 try_to_grow_stack = !noninteractive || initialized;
856#endif
857 1042
858 if (try_to_grow_stack) 1043 if (try_to_grow_stack)
859 { 1044 {
@@ -1184,17 +1369,15 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1184 1369
1185#if defined HAVE_PTHREAD && !defined SYSTEM_MALLOC \ 1370#if defined HAVE_PTHREAD && !defined SYSTEM_MALLOC \
1186 && !defined DOUG_LEA_MALLOC && !defined HYBRID_MALLOC 1371 && !defined DOUG_LEA_MALLOC && !defined HYBRID_MALLOC
1187# ifndef CANNOT_DUMP
1188 /* Do not make gmalloc thread-safe when creating bootstrap-emacs, as 1372 /* Do not make gmalloc thread-safe when creating bootstrap-emacs, as
1189 that causes an infinite recursive loop with FreeBSD. See 1373 that causes an infinite recursive loop with FreeBSD. See
1190 Bug#14569. The part of this bug involving Cygwin is no longer 1374 Bug#14569. The part of this bug involving Cygwin is no longer
1191 relevant, now that Cygwin defines HYBRID_MALLOC. */ 1375 relevant, now that Cygwin defines HYBRID_MALLOC. */
1192 if (!noninteractive || initialized) 1376 if (!noninteractive || !will_dump_p ())
1193# endif
1194 malloc_enable_thread (); 1377 malloc_enable_thread ();
1195#endif 1378#endif
1196 1379
1197 init_signals (dumping); 1380 init_signals ();
1198 1381
1199 noninteractive1 = noninteractive; 1382 noninteractive1 = noninteractive;
1200 1383
@@ -1204,7 +1387,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1204 { 1387 {
1205 init_alloc_once (); 1388 init_alloc_once ();
1206 init_threads_once (); 1389 init_threads_once ();
1207 init_obarray (); 1390 init_obarray_once ();
1208 init_eval_once (); 1391 init_eval_once ();
1209 init_charset_once (); 1392 init_charset_once ();
1210 init_coding_once (); 1393 init_coding_once ();
@@ -1242,7 +1425,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1242 /* Before init_window_once, because it sets up the 1425 /* Before init_window_once, because it sets up the
1243 Vcoding_system_hash_table. */ 1426 Vcoding_system_hash_table. */
1244 syms_of_coding (); /* This should be after syms_of_fileio. */ 1427 syms_of_coding (); /* This should be after syms_of_fileio. */
1245 1428 init_frame_once (); /* Before init_window_once. */
1246 init_window_once (); /* Init the window system. */ 1429 init_window_once (); /* Init the window system. */
1247#ifdef HAVE_WINDOW_SYSTEM 1430#ifdef HAVE_WINDOW_SYSTEM
1248 init_fringe_once (); /* Swap bitmaps if necessary. */ 1431 init_fringe_once (); /* Swap bitmaps if necessary. */
@@ -1282,7 +1465,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1282 bool module_assertions 1465 bool module_assertions
1283 = argmatch (argv, argc, "-module-assertions", "--module-assertions", 15, 1466 = argmatch (argv, argc, "-module-assertions", "--module-assertions", 15,
1284 NULL, &skip_args); 1467 NULL, &skip_args);
1285 if (dumping && module_assertions) 1468 if (will_dump_p () && module_assertions)
1286 { 1469 {
1287 fputs ("Module assertions are not supported during dumping\n", stderr); 1470 fputs ("Module assertions are not supported during dumping\n", stderr);
1288 exit (1); 1471 exit (1);
@@ -1419,7 +1602,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1419 /* egetenv is a pretty low-level facility, which may get called in 1602 /* egetenv is a pretty low-level facility, which may get called in
1420 many circumstances; it seems flimsy to put off initializing it 1603 many circumstances; it seems flimsy to put off initializing it
1421 until calling init_callproc. Do not do it when dumping. */ 1604 until calling init_callproc. Do not do it when dumping. */
1422 if (! dumping) 1605 if (!will_dump_p ())
1423 set_initial_environment (); 1606 set_initial_environment ();
1424 1607
1425#ifdef WINDOWSNT 1608#ifdef WINDOWSNT
@@ -1433,7 +1616,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1433 variables from the parent process without modifications from 1616 variables from the parent process without modifications from
1434 Emacs. */ 1617 Emacs. */
1435 init_environment (argv); 1618 init_environment (argv);
1436 init_ntproc (dumping); /* must precede init_editfns. */ 1619 init_ntproc (will_dump_p ()); /* must precede init_editfns. */
1437#endif 1620#endif
1438 1621
1439 /* AIX crashes are reported in system versions 3.2.3 and 3.2.4 1622 /* AIX crashes are reported in system versions 3.2.3 and 3.2.4
@@ -1445,7 +1628,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1445#endif 1628#endif
1446 1629
1447 /* Init buffer storage and default directory of main buffer. */ 1630 /* Init buffer storage and default directory of main buffer. */
1448 init_buffer (initialized); 1631 init_buffer ();
1449 1632
1450 init_callproc_1 (); /* Must precede init_cmdargs and init_sys_modes. */ 1633 init_callproc_1 (); /* Must precede init_cmdargs and init_sys_modes. */
1451 1634
@@ -1620,6 +1803,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1620 1803
1621 syms_of_threads (); 1804 syms_of_threads ();
1622 syms_of_profiler (); 1805 syms_of_profiler ();
1806 syms_of_pdumper ();
1623 1807
1624#ifdef HAVE_JSON 1808#ifdef HAVE_JSON
1625 syms_of_json (); 1809 syms_of_json ();
@@ -1650,7 +1834,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1650 init_charset (); 1834 init_charset ();
1651 1835
1652 /* This calls putenv and so must precede init_process_emacs. */ 1836 /* This calls putenv and so must precede init_process_emacs. */
1653 init_timefns (dumping); 1837 init_timefns ();
1654 1838
1655 /* This sets Voperating_system_release, which init_process_emacs uses. */ 1839 /* This sets Voperating_system_release, which init_process_emacs uses. */
1656 init_editfns (); 1840 init_editfns ();
@@ -1669,10 +1853,9 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1669 init_process_emacs (sockfd); 1853 init_process_emacs (sockfd);
1670 1854
1671 init_keyboard (); /* This too must precede init_sys_modes. */ 1855 init_keyboard (); /* This too must precede init_sys_modes. */
1672 if (!noninteractive) 1856 init_display (); /* Determine terminal type. Calls init_sys_modes. */
1673 init_display (); /* Determine terminal type. Calls init_sys_modes. */
1674#if HAVE_W32NOTIFY 1857#if HAVE_W32NOTIFY
1675 else 1858 if (noninteractive)
1676 init_crit (); /* w32notify.c needs this in batch mode. */ 1859 init_crit (); /* w32notify.c needs this in batch mode. */
1677#endif /* HAVE_W32NOTIFY */ 1860#endif /* HAVE_W32NOTIFY */
1678 init_xdisp (); 1861 init_xdisp ();
@@ -1716,7 +1899,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1716 moncontrol (0); 1899 moncontrol (0);
1717#endif 1900#endif
1718 1901
1719 initialized = 1; 1902 initialized = true;
1903
1904 if (dump_mode)
1905 Vdump_mode = build_string (dump_mode);
1720 1906
1721 /* Enter editor command loop. This never returns. */ 1907 /* Enter editor command loop. This never returns. */
1722 Frecursive_edit (); 1908 Frecursive_edit ();
@@ -2166,8 +2352,11 @@ You must run Emacs in batch mode in order to dump it. */)
2166 if (! noninteractive) 2352 if (! noninteractive)
2167 error ("Dumping Emacs works only in batch mode"); 2353 error ("Dumping Emacs works only in batch mode");
2168 2354
2169 if (!might_dump) 2355 if (dumped_with_unexec_p ())
2170 error ("Emacs can be dumped only once"); 2356 error ("Emacs can be dumped using unexec only once");
2357
2358 if (definitely_will_not_unexec_p ())
2359 error ("This Emacs instance was not started in temacs mode");
2171 2360
2172#if defined GNU_LINUX && !defined CANNOT_DUMP 2361#if defined GNU_LINUX && !defined CANNOT_DUMP
2173 2362
@@ -2231,12 +2420,19 @@ You must run Emacs in batch mode in order to dump it. */)
2231#endif /* not WINDOWSNT */ 2420#endif /* not WINDOWSNT */
2232#endif /* not SYSTEM_MALLOC and not HYBRID_MALLOC */ 2421#endif /* not SYSTEM_MALLOC and not HYBRID_MALLOC */
2233 2422
2423 struct gflags old_gflags = gflags;
2424 gflags.will_dump_ = false;
2425 gflags.will_dump_with_unexec_ = false;
2426 gflags.dumped_with_unexec_ = true;
2427
2234 alloc_unexec_pre (); 2428 alloc_unexec_pre ();
2235 2429
2236 unexec (SSDATA (filename), !NILP (symfile) ? SSDATA (symfile) : 0); 2430 unexec (SSDATA (filename), !NILP (symfile) ? SSDATA (symfile) : 0);
2237 2431
2238 alloc_unexec_post (); 2432 alloc_unexec_post ();
2239 2433
2434 gflags = old_gflags;
2435
2240#ifdef WINDOWSNT 2436#ifdef WINDOWSNT
2241 Vlibrary_cache = Qnil; 2437 Vlibrary_cache = Qnil;
2242#endif 2438#endif
@@ -2250,6 +2446,7 @@ You must run Emacs in batch mode in order to dump it. */)
2250} 2446}
2251 2447
2252#endif /* not CANNOT_DUMP */ 2448#endif /* not CANNOT_DUMP */
2449
2253 2450
2254#if HAVE_SETLOCALE 2451#if HAVE_SETLOCALE
2255/* Recover from setlocale (LC_ALL, ""). */ 2452/* Recover from setlocale (LC_ALL, ""). */
@@ -2585,7 +2782,7 @@ Don't rely on it for testing whether a feature you want to use is available. */
2585 Vsystem_configuration_features = build_string (EMACS_CONFIG_FEATURES); 2782 Vsystem_configuration_features = build_string (EMACS_CONFIG_FEATURES);
2586 2783
2587 DEFVAR_BOOL ("noninteractive", noninteractive1, 2784 DEFVAR_BOOL ("noninteractive", noninteractive1,
2588 doc: /* Non-nil means Emacs is running without interactive terminal. */); 2785 doc: /* Non-nil means Emacs is running without interactive terminal. */);
2589 2786
2590 DEFVAR_LISP ("kill-emacs-hook", Vkill_emacs_hook, 2787 DEFVAR_LISP ("kill-emacs-hook", Vkill_emacs_hook,
2591 doc: /* Hook run when `kill-emacs' is called. 2788 doc: /* Hook run when `kill-emacs' is called.
@@ -2670,6 +2867,9 @@ component .BUILD is present. This is now stored separately in
2670 doc: /* Address of mailing list for GNU Emacs bugs. */); 2867 doc: /* Address of mailing list for GNU Emacs bugs. */);
2671 Vreport_emacs_bug_address = build_string (emacs_bugreport); 2868 Vreport_emacs_bug_address = build_string (emacs_bugreport);
2672 2869
2870 DEFVAR_LISP ("dump-mode", Vdump_mode,
2871 doc: /* Non-nil when Emacs is dumping itself. */);
2872
2673 DEFVAR_LISP ("dynamic-library-alist", Vdynamic_library_alist, 2873 DEFVAR_LISP ("dynamic-library-alist", Vdynamic_library_alist,
2674 doc: /* Alist of dynamic libraries vs external files implementing them. 2874 doc: /* Alist of dynamic libraries vs external files implementing them.
2675Each element is a list (LIBRARY FILE...), where the car is a symbol 2875Each element is a list (LIBRARY FILE...), where the car is a symbol
diff --git a/src/eval.c b/src/eval.c
index 28478956e35..b094fc2e663 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -29,6 +29,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
29#include "keyboard.h" 29#include "keyboard.h"
30#include "dispextern.h" 30#include "dispextern.h"
31#include "buffer.h" 31#include "buffer.h"
32#include "pdumper.h"
32 33
33/* CACHEABLE is ordinarily nothing, except it is 'volatile' if 34/* CACHEABLE is ordinarily nothing, except it is 'volatile' if
34 necessary to cajole GCC into not warning incorrectly that a 35 necessary to cajole GCC into not warning incorrectly that a
@@ -89,10 +90,6 @@ static EMACS_INT when_entered_debugger;
89/* FIXME: We should probably get rid of this! */ 90/* FIXME: We should probably get rid of this! */
90Lisp_Object Vsignaling_function; 91Lisp_Object Vsignaling_function;
91 92
92/* If non-nil, Lisp code must not be run since some part of Emacs is in
93 an inconsistent state. Currently unused. */
94Lisp_Object inhibit_lisp_code;
95
96/* These would ordinarily be static, but they need to be visible to GDB. */ 93/* These would ordinarily be static, but they need to be visible to GDB. */
97bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE; 94bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE;
98Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE; 95Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE;
@@ -235,6 +232,8 @@ backtrace_next (union specbinding *pdl)
235 return pdl; 232 return pdl;
236} 233}
237 234
235static void init_eval_once_for_pdumper (void);
236
238static union specbinding * 237static union specbinding *
239backtrace_thread_next (struct thread_state *tstate, union specbinding *pdl) 238backtrace_thread_next (struct thread_state *tstate, union specbinding *pdl)
240{ 239{
@@ -247,15 +246,20 @@ backtrace_thread_next (struct thread_state *tstate, union specbinding *pdl)
247void 246void
248init_eval_once (void) 247init_eval_once (void)
249{ 248{
250 enum { size = 50 };
251 union specbinding *pdlvec = xmalloc ((size + 1) * sizeof *specpdl);
252 specpdl_size = size;
253 specpdl = specpdl_ptr = pdlvec + 1;
254 /* Don't forget to update docs (lispref node "Local Variables"). */ 249 /* Don't forget to update docs (lispref node "Local Variables"). */
255 max_specpdl_size = 1300; /* 1000 is not enough for CEDET's c-by.el. */ 250 max_specpdl_size = 1300; /* 1000 is not enough for CEDET's c-by.el. */
256 max_lisp_eval_depth = 800; 251 max_lisp_eval_depth = 800;
257
258 Vrun_hooks = Qnil; 252 Vrun_hooks = Qnil;
253 pdumper_do_now_and_after_load (init_eval_once_for_pdumper);
254}
255
256static void
257init_eval_once_for_pdumper (void)
258{
259 enum { size = 50 };
260 union specbinding *pdlvec = malloc ((size + 1) * sizeof *specpdl);
261 specpdl_size = size;
262 specpdl = specpdl_ptr = pdlvec + 1;
259} 263}
260 264
261/* static struct handler handlerlist_sentinel; */ 265/* static struct handler handlerlist_sentinel; */
@@ -2084,7 +2088,7 @@ it defines a macro. */)
2084 2088
2085 /* This is to make sure that loadup.el gives a clear picture 2089 /* This is to make sure that loadup.el gives a clear picture
2086 of what files are preloaded and when. */ 2090 of what files are preloaded and when. */
2087 if (! NILP (Vpurify_flag)) 2091 if (will_dump_p () && !will_bootstrap_p ())
2088 error ("Attempt to autoload %s while preparing to dump", 2092 error ("Attempt to autoload %s while preparing to dump",
2089 SDATA (SYMBOL_NAME (funname))); 2093 SDATA (SYMBOL_NAME (funname)));
2090 2094
@@ -4002,7 +4006,7 @@ mark_specpdl (union specbinding *first, union specbinding *ptr)
4002 for (pdl = first; pdl != ptr; pdl++) 4006 for (pdl = first; pdl != ptr; pdl++)
4003 { 4007 {
4004 switch (pdl->kind) 4008 switch (pdl->kind)
4005 { 4009 {
4006 case SPECPDL_UNWIND: 4010 case SPECPDL_UNWIND:
4007 mark_object (specpdl_arg (pdl)); 4011 mark_object (specpdl_arg (pdl));
4008 break; 4012 break;
@@ -4039,7 +4043,7 @@ mark_specpdl (union specbinding *first, union specbinding *ptr)
4039 4043
4040 case SPECPDL_UNWIND_PTR: 4044 case SPECPDL_UNWIND_PTR:
4041 case SPECPDL_UNWIND_INT: 4045 case SPECPDL_UNWIND_INT:
4042 case SPECPDL_UNWIND_VOID: 4046 case SPECPDL_UNWIND_VOID:
4043 break; 4047 break;
4044 4048
4045 default: 4049 default:
@@ -4225,8 +4229,6 @@ alist of active lexical bindings. */);
4225 staticpro (&Vsignaling_function); 4229 staticpro (&Vsignaling_function);
4226 Vsignaling_function = Qnil; 4230 Vsignaling_function = Qnil;
4227 4231
4228 inhibit_lisp_code = Qnil;
4229
4230 DEFSYM (Qcatch_all_memory_full, "catch-all-memory-full"); 4232 DEFSYM (Qcatch_all_memory_full, "catch-all-memory-full");
4231 Funintern (Qcatch_all_memory_full, Qnil); 4233 Funintern (Qcatch_all_memory_full, Qnil);
4232 4234
diff --git a/src/filelock.c b/src/filelock.c
index 81d98f36fa4..64310f5c538 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -171,13 +171,10 @@ get_boot_time (void)
171 } 171 }
172 172
173#if defined (BOOT_TIME) 173#if defined (BOOT_TIME)
174#ifndef CANNOT_DUMP 174 /* The utmp routines maintain static state. Don't touch that state
175 /* The utmp routines maintain static state. 175 if we are going to dump, since it might not survive dumping. */
176 Don't touch that state unless we are initialized, 176 if (will_dump_p ())
177 since it might not survive dumping. */
178 if (! initialized)
179 return boot_time; 177 return boot_time;
180#endif /* not CANNOT_DUMP */
181 178
182 /* Try to get boot time from utmp before wtmp, 179 /* Try to get boot time from utmp before wtmp,
183 since utmp is typically much smaller than wtmp. 180 since utmp is typically much smaller than wtmp.
@@ -666,7 +663,7 @@ lock_file (Lisp_Object fn)
666 /* Don't do locking while dumping Emacs. 663 /* Don't do locking while dumping Emacs.
667 Uncompressing wtmp files uses call-process, which does not work 664 Uncompressing wtmp files uses call-process, which does not work
668 in an uninitialized Emacs. */ 665 in an uninitialized Emacs. */
669 if (! NILP (Vpurify_flag)) 666 if (will_dump_p ())
670 return; 667 return;
671 668
672 orig_fn = fn; 669 orig_fn = fn;
diff --git a/src/fingerprint-dummy.c b/src/fingerprint-dummy.c
new file mode 100644
index 00000000000..295654a40db
--- /dev/null
+++ b/src/fingerprint-dummy.c
@@ -0,0 +1,24 @@
1/* Dummy fingerprint
2
3Copyright (C) 2016 Free Software Foundation,
4Inc.
5
6This file is part of GNU Emacs.
7
8GNU Emacs is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or (at
11your option) any later version.
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20
21#include "fingerprint.h"
22
23/* Dummy fingerprint to use as hash input. */
24const uint8_t fingerprint[32] = { 0 };
diff --git a/src/fingerprint.h b/src/fingerprint.h
new file mode 100644
index 00000000000..b48d40f89ca
--- /dev/null
+++ b/src/fingerprint.h
@@ -0,0 +1,32 @@
1/* Header file for the Emacs build fingerprint.
2
3Copyright (C) 2016 Free Software Foundation,
4Inc.
5
6This file is part of GNU Emacs.
7
8GNU Emacs is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or (at
11your option) any later version.
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20
21#ifndef EMACS_FINGERPRINT_H
22#define EMACS_FINGERPRINT_H
23
24#include <stdint.h>
25
26/* We generate fingerprint.c and fingerprint.o from all the sources in
27 Emacs. This way, we have a unique value that we can use to pair
28 data files (like a portable dump image) with a specific build of
29 Emacs. */
30extern const uint8_t fingerprint[32];
31
32#endif
diff --git a/src/fns.c b/src/fns.c
index 6fcb38e4b04..1ac60321c58 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -2949,7 +2949,7 @@ suppressed. */)
2949 2949
2950 /* This is to make sure that loadup.el gives a clear picture 2950 /* This is to make sure that loadup.el gives a clear picture
2951 of what files are preloaded and when. */ 2951 of what files are preloaded and when. */
2952 if (! NILP (Vpurify_flag)) 2952 if (will_dump_p () && !will_bootstrap_p ())
2953 error ("(require %s) while preparing to dump", 2953 error ("(require %s) while preparing to dump",
2954 SDATA (SYMBOL_NAME (feature))); 2954 SDATA (SYMBOL_NAME (feature)));
2955 2955
@@ -3648,10 +3648,6 @@ base64_decode_1 (const char *from, char *to, ptrdiff_t length,
3648 if a `:linear-search t' argument is given to make-hash-table. */ 3648 if a `:linear-search t' argument is given to make-hash-table. */
3649 3649
3650 3650
3651/* The list of all weak hash tables. Don't staticpro this one. */
3652
3653static struct Lisp_Hash_Table *weak_hash_tables;
3654
3655 3651
3656/*********************************************************************** 3652/***********************************************************************
3657 Utilities 3653 Utilities
@@ -3866,7 +3862,7 @@ hashfn_eq (struct hash_table_test *ht, Lisp_Object key)
3866 `equal' to compare keys. The hash code returned is guaranteed to fit 3862 `equal' to compare keys. The hash code returned is guaranteed to fit
3867 in a Lisp integer. */ 3863 in a Lisp integer. */
3868 3864
3869static EMACS_UINT 3865EMACS_UINT
3870hashfn_equal (struct hash_table_test *ht, Lisp_Object key) 3866hashfn_equal (struct hash_table_test *ht, Lisp_Object key)
3871{ 3867{
3872 return sxhash (key, 0); 3868 return sxhash (key, 0);
@@ -3876,7 +3872,7 @@ hashfn_equal (struct hash_table_test *ht, Lisp_Object key)
3876 `eql' to compare keys. The hash code returned is guaranteed to fit 3872 `eql' to compare keys. The hash code returned is guaranteed to fit
3877 in a Lisp integer. */ 3873 in a Lisp integer. */
3878 3874
3879static EMACS_UINT 3875EMACS_UINT
3880hashfn_eql (struct hash_table_test *ht, Lisp_Object key) 3876hashfn_eql (struct hash_table_test *ht, Lisp_Object key)
3881{ 3877{
3882 return ((FLOATP (key) || BIGNUMP (key)) 3878 return ((FLOATP (key) || BIGNUMP (key))
@@ -3984,6 +3980,7 @@ make_hash_table (struct hash_table_test test, EMACS_INT size,
3984 h->hash = make_nil_vector (size); 3980 h->hash = make_nil_vector (size);
3985 h->next = make_vector (size, make_fixnum (-1)); 3981 h->next = make_vector (size, make_fixnum (-1));
3986 h->index = make_vector (index_size, make_fixnum (-1)); 3982 h->index = make_vector (index_size, make_fixnum (-1));
3983 h->next_weak = NULL;
3987 h->pure = pure; 3984 h->pure = pure;
3988 3985
3989 /* Set up the free list. */ 3986 /* Set up the free list. */
@@ -3995,13 +3992,6 @@ make_hash_table (struct hash_table_test test, EMACS_INT size,
3995 eassert (HASH_TABLE_P (table)); 3992 eassert (HASH_TABLE_P (table));
3996 eassert (XHASH_TABLE (table) == h); 3993 eassert (XHASH_TABLE (table) == h);
3997 3994
3998 /* Maybe add this hash table to the list of all weak hash tables. */
3999 if (! NILP (weak))
4000 {
4001 h->next_weak = weak_hash_tables;
4002 weak_hash_tables = h;
4003 }
4004
4005 return table; 3995 return table;
4006} 3996}
4007 3997
@@ -4023,13 +4013,6 @@ copy_hash_table (struct Lisp_Hash_Table *h1)
4023 h2->index = Fcopy_sequence (h1->index); 4013 h2->index = Fcopy_sequence (h1->index);
4024 XSET_HASH_TABLE (table, h2); 4014 XSET_HASH_TABLE (table, h2);
4025 4015
4026 /* Maybe add this hash table to the list of all weak hash tables. */
4027 if (!NILP (h2->weak))
4028 {
4029 h2->next_weak = h1->next_weak;
4030 h1->next_weak = h2;
4031 }
4032
4033 return table; 4016 return table;
4034} 4017}
4035 4018
@@ -4115,6 +4098,43 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
4115 } 4098 }
4116} 4099}
4117 4100
4101void
4102hash_table_rehash (struct Lisp_Hash_Table *h)
4103{
4104 ptrdiff_t size = HASH_TABLE_SIZE (h);
4105
4106 /* Recompute the actual hash codes for each entry in the table.
4107 Order is still invalid. */
4108 for (ptrdiff_t i = 0; i < size; ++i)
4109 if (!NILP (HASH_HASH (h, i)))
4110 {
4111 Lisp_Object key = HASH_KEY (h, i);
4112 EMACS_UINT hash_code = h->test.hashfn (&h->test, key);
4113 set_hash_hash_slot (h, i, make_fixnum (hash_code));
4114 }
4115
4116 /* Reset the index so that any slot we don't fill below is marked
4117 invalid. */
4118 Ffillarray (h->index, make_fixnum (-1));
4119
4120 /* Rebuild the collision chains. */
4121 for (ptrdiff_t i = 0; i < size; ++i)
4122 if (!NILP (HASH_HASH (h, i)))
4123 {
4124 EMACS_UINT hash_code = XUFIXNUM (HASH_HASH (h, i));
4125 ptrdiff_t start_of_bucket = hash_code % ASIZE (h->index);
4126 set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
4127 set_hash_index_slot (h, start_of_bucket, i);
4128 eassert (HASH_NEXT (h, i) != i); /* Stop loops. */
4129 }
4130
4131 /* Finally, mark the hash table as having a valid hash order.
4132 Do this last so that if we're interrupted, we retry on next
4133 access. */
4134 eassert (h->count < 0);
4135 h->count = -h->count;
4136 eassert (!hash_rehash_needed_p (h));
4137}
4118 4138
4119/* Lookup KEY in hash table H. If HASH is non-null, return in *HASH 4139/* Lookup KEY in hash table H. If HASH is non-null, return in *HASH
4120 the hash code of KEY. Value is the index of the entry in H 4140 the hash code of KEY. Value is the index of the entry in H
@@ -4126,6 +4146,8 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash)
4126 EMACS_UINT hash_code; 4146 EMACS_UINT hash_code;
4127 ptrdiff_t start_of_bucket, i; 4147 ptrdiff_t start_of_bucket, i;
4128 4148
4149 hash_rehash_if_needed (h);
4150
4129 hash_code = h->test.hashfn (&h->test, key); 4151 hash_code = h->test.hashfn (&h->test, key);
4130 eassert ((hash_code & ~INTMASK) == 0); 4152 eassert ((hash_code & ~INTMASK) == 0);
4131 if (hash) 4153 if (hash)
@@ -4154,6 +4176,8 @@ hash_put (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object value,
4154{ 4176{
4155 ptrdiff_t start_of_bucket, i; 4177 ptrdiff_t start_of_bucket, i;
4156 4178
4179 hash_rehash_if_needed (h);
4180
4157 eassert ((hash & ~INTMASK) == 0); 4181 eassert ((hash & ~INTMASK) == 0);
4158 4182
4159 /* Increment count after resizing because resizing may fail. */ 4183 /* Increment count after resizing because resizing may fail. */
@@ -4187,6 +4211,8 @@ hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key)
4187 ptrdiff_t start_of_bucket = hash_code % ASIZE (h->index); 4211 ptrdiff_t start_of_bucket = hash_code % ASIZE (h->index);
4188 ptrdiff_t prev = -1; 4212 ptrdiff_t prev = -1;
4189 4213
4214 hash_rehash_if_needed (h);
4215
4190 for (ptrdiff_t i = HASH_INDEX (h, start_of_bucket); 4216 for (ptrdiff_t i = HASH_INDEX (h, start_of_bucket);
4191 0 <= i; 4217 0 <= i;
4192 i = HASH_NEXT (h, i)) 4218 i = HASH_NEXT (h, i))
@@ -4255,7 +4281,7 @@ hash_clear (struct Lisp_Hash_Table *h)
4255 !REMOVE_ENTRIES_P means mark entries that are in use. Value is 4281 !REMOVE_ENTRIES_P means mark entries that are in use. Value is
4256 true if anything was marked. */ 4282 true if anything was marked. */
4257 4283
4258static bool 4284bool
4259sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p) 4285sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
4260{ 4286{
4261 ptrdiff_t n = gc_asize (h->index); 4287 ptrdiff_t n = gc_asize (h->index);
@@ -4263,12 +4289,14 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
4263 4289
4264 for (ptrdiff_t bucket = 0; bucket < n; ++bucket) 4290 for (ptrdiff_t bucket = 0; bucket < n; ++bucket)
4265 { 4291 {
4266 /* Follow collision chain, removing entries that 4292 /* Follow collision chain, removing entries that don't survive
4267 don't survive this garbage collection. */ 4293 this garbage collection. It's okay if hash_rehash_needed_p
4294 (h) is true, since we're operating entirely on the cached
4295 hash values. */
4268 ptrdiff_t prev = -1; 4296 ptrdiff_t prev = -1;
4269 ptrdiff_t next; 4297 ptrdiff_t next;
4270 for (ptrdiff_t i = HASH_INDEX (h, bucket); 0 <= i; i = next) 4298 for (ptrdiff_t i = HASH_INDEX (h, bucket); 0 <= i; i = next)
4271 { 4299 {
4272 bool key_known_to_survive_p = survives_gc_p (HASH_KEY (h, i)); 4300 bool key_known_to_survive_p = survives_gc_p (HASH_KEY (h, i));
4273 bool value_known_to_survive_p = survives_gc_p (HASH_VALUE (h, i)); 4301 bool value_known_to_survive_p = survives_gc_p (HASH_VALUE (h, i));
4274 bool remove_p; 4302 bool remove_p;
@@ -4303,10 +4331,11 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
4303 /* Clear key, value, and hash. */ 4331 /* Clear key, value, and hash. */
4304 set_hash_key_slot (h, i, Qnil); 4332 set_hash_key_slot (h, i, Qnil);
4305 set_hash_value_slot (h, i, Qnil); 4333 set_hash_value_slot (h, i, Qnil);
4306 set_hash_hash_slot (h, i, Qnil); 4334 set_hash_hash_slot (h, i, Qnil);
4307 4335
4308 h->count--; 4336 eassert (h->count != 0);
4309 } 4337 h->count += h->count > 0 ? -1 : 1;
4338 }
4310 else 4339 else
4311 { 4340 {
4312 prev = i; 4341 prev = i;
@@ -4320,13 +4349,13 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
4320 if (!key_known_to_survive_p) 4349 if (!key_known_to_survive_p)
4321 { 4350 {
4322 mark_object (HASH_KEY (h, i)); 4351 mark_object (HASH_KEY (h, i));
4323 marked = 1; 4352 marked = true;
4324 } 4353 }
4325 4354
4326 if (!value_known_to_survive_p) 4355 if (!value_known_to_survive_p)
4327 { 4356 {
4328 mark_object (HASH_VALUE (h, i)); 4357 mark_object (HASH_VALUE (h, i));
4329 marked = 1; 4358 marked = true;
4330 } 4359 }
4331 } 4360 }
4332 } 4361 }
@@ -4336,55 +4365,6 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
4336 return marked; 4365 return marked;
4337} 4366}
4338 4367
4339/* Remove elements from weak hash tables that don't survive the
4340 current garbage collection. Remove weak tables that don't survive
4341 from Vweak_hash_tables. Called from gc_sweep. */
4342
4343NO_INLINE /* For better stack traces */
4344void
4345sweep_weak_hash_tables (void)
4346{
4347 struct Lisp_Hash_Table *h, *used, *next;
4348 bool marked;
4349
4350 /* Mark all keys and values that are in use. Keep on marking until
4351 there is no more change. This is necessary for cases like
4352 value-weak table A containing an entry X -> Y, where Y is used in a
4353 key-weak table B, Z -> Y. If B comes after A in the list of weak
4354 tables, X -> Y might be removed from A, although when looking at B
4355 one finds that it shouldn't. */
4356 do
4357 {
4358 marked = 0;
4359 for (h = weak_hash_tables; h; h = h->next_weak)
4360 {
4361 if (h->header.size & ARRAY_MARK_FLAG)
4362 marked |= sweep_weak_table (h, 0);
4363 }
4364 }
4365 while (marked);
4366
4367 /* Remove tables and entries that aren't used. */
4368 for (h = weak_hash_tables, used = NULL; h; h = next)
4369 {
4370 next = h->next_weak;
4371
4372 if (h->header.size & ARRAY_MARK_FLAG)
4373 {
4374 /* TABLE is marked as used. Sweep its contents. */
4375 if (h->count > 0)
4376 sweep_weak_table (h, 1);
4377
4378 /* Add table to the list of used weak hash tables. */
4379 h->next_weak = used;
4380 used = h;
4381 }
4382 }
4383
4384 weak_hash_tables = used;
4385}
4386
4387
4388 4368
4389/*********************************************************************** 4369/***********************************************************************
4390 Hash Code Computation 4370 Hash Code Computation
@@ -5294,6 +5274,7 @@ disregarding any coding systems. If nil, use the current buffer. */ )
5294} 5274}
5295 5275
5296 5276
5277
5297void 5278void
5298syms_of_fns (void) 5279syms_of_fns (void)
5299{ 5280{
diff --git a/src/font.c b/src/font.c
index 3fc77a1d76a..4ca44942fde 100644
--- a/src/font.c
+++ b/src/font.c
@@ -38,6 +38,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
38#include "fontset.h" 38#include "fontset.h"
39#include "font.h" 39#include "font.h"
40#include "termhooks.h" 40#include "termhooks.h"
41#include "pdumper.h"
41 42
42#ifdef HAVE_WINDOW_SYSTEM 43#ifdef HAVE_WINDOW_SYSTEM
43#include TERM_HEADER 44#include TERM_HEADER
@@ -5309,9 +5310,10 @@ syms_of_font (void)
5309 sort_shift_bits[FONT_SIZE_INDEX] = 16; 5310 sort_shift_bits[FONT_SIZE_INDEX] = 16;
5310 sort_shift_bits[FONT_WIDTH_INDEX] = 23; 5311 sort_shift_bits[FONT_WIDTH_INDEX] = 23;
5311 /* Note that the other elements in sort_shift_bits are not used. */ 5312 /* Note that the other elements in sort_shift_bits are not used. */
5313 PDUMPER_REMEMBER_SCALAR (sort_shift_bits);
5312 5314
5313 staticpro (&font_charset_alist);
5314 font_charset_alist = Qnil; 5315 font_charset_alist = Qnil;
5316 staticpro (&font_charset_alist);
5315 5317
5316 DEFSYM (Qopentype, "opentype"); 5318 DEFSYM (Qopentype, "opentype");
5317 5319
@@ -5349,13 +5351,13 @@ syms_of_font (void)
5349 5351
5350 DEFSYM (QCuser_spec, ":user-spec"); 5352 DEFSYM (QCuser_spec, ":user-spec");
5351 5353
5352 staticpro (&scratch_font_spec);
5353 scratch_font_spec = Ffont_spec (0, NULL); 5354 scratch_font_spec = Ffont_spec (0, NULL);
5354 staticpro (&scratch_font_prefer); 5355 staticpro (&scratch_font_spec);
5355 scratch_font_prefer = Ffont_spec (0, NULL); 5356 scratch_font_prefer = Ffont_spec (0, NULL);
5357 staticpro (&scratch_font_prefer);
5356 5358
5357 staticpro (&Vfont_log_deferred);
5358 Vfont_log_deferred = make_nil_vector (3); 5359 Vfont_log_deferred = make_nil_vector (3);
5360 staticpro (&Vfont_log_deferred);
5359 5361
5360#if 0 5362#if 0
5361#ifdef HAVE_LIBOTF 5363#ifdef HAVE_LIBOTF
diff --git a/src/fontset.c b/src/fontset.c
index 55a3f78e865..2729fae6ee9 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -39,6 +39,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
39#include TERM_HEADER 39#include TERM_HEADER
40#endif /* HAVE_WINDOW_SYSTEM */ 40#endif /* HAVE_WINDOW_SYSTEM */
41#include "font.h" 41#include "font.h"
42#include "pdumper.h"
42 43
43/* FONTSET 44/* FONTSET
44 45
@@ -2127,6 +2128,7 @@ syms_of_fontset (void)
2127 build_pure_c_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default")); 2128 build_pure_c_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
2128 ASET (Vfontset_table, 0, Vdefault_fontset); 2129 ASET (Vfontset_table, 0, Vdefault_fontset);
2129 next_fontset_id = 1; 2130 next_fontset_id = 1;
2131 PDUMPER_REMEMBER_SCALAR (next_fontset_id);
2130 2132
2131 auto_fontset_alist = Qnil; 2133 auto_fontset_alist = Qnil;
2132 staticpro (&auto_fontset_alist); 2134 staticpro (&auto_fontset_alist);
diff --git a/src/frame.c b/src/frame.c
index 6d93abd09bf..aa1a15ff006 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -53,6 +53,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
53#ifdef USE_X_TOOLKIT 53#ifdef USE_X_TOOLKIT
54#include "widget.h" 54#include "widget.h"
55#endif 55#endif
56#include "pdumper.h"
56 57
57/* The currently selected frame. */ 58/* The currently selected frame. */
58Lisp_Object selected_frame; 59Lisp_Object selected_frame;
@@ -1051,10 +1052,7 @@ make_initial_frame (void)
1051 Lisp_Object frame; 1052 Lisp_Object frame;
1052 1053
1053 eassert (initial_kboard); 1054 eassert (initial_kboard);
1054 1055 eassert (NILP (Vframe_list) || CONSP (Vframe_list));
1055 /* The first call must initialize Vframe_list. */
1056 if (! (NILP (Vframe_list) || CONSP (Vframe_list)))
1057 Vframe_list = Qnil;
1058 1056
1059 terminal = init_initial_terminal (); 1057 terminal = init_initial_terminal ();
1060 1058
@@ -5626,6 +5624,26 @@ make_monitor_attribute_list (struct MonitorInfo *monitors,
5626 Initialization 5624 Initialization
5627 ***********************************************************************/ 5625 ***********************************************************************/
5628 5626
5627static void init_frame_once_for_pdumper (void);
5628
5629void
5630init_frame_once (void)
5631{
5632 staticpro (&Vframe_list);
5633 staticpro (&selected_frame);
5634 PDUMPER_IGNORE (last_nonminibuf_frame);
5635 Vframe_list = Qnil;
5636 selected_frame = Qnil;
5637 pdumper_do_now_and_after_load (init_frame_once_for_pdumper);
5638}
5639
5640static void
5641init_frame_once_for_pdumper (void)
5642{
5643 PDUMPER_RESET_LV (Vframe_list, Qnil);
5644 PDUMPER_RESET_LV (selected_frame, Qnil);
5645}
5646
5629void 5647void
5630syms_of_frame (void) 5648syms_of_frame (void)
5631{ 5649{
@@ -6107,8 +6125,6 @@ making the child frame unresponsive to user actions, the default is to
6107iconify the top level frame instead. */); 6125iconify the top level frame instead. */);
6108 iconify_child_frame = Qiconify_top_level; 6126 iconify_child_frame = Qiconify_top_level;
6109 6127
6110 staticpro (&Vframe_list);
6111
6112 defsubr (&Sframep); 6128 defsubr (&Sframep);
6113 defsubr (&Sframe_live_p); 6129 defsubr (&Sframe_live_p);
6114 defsubr (&Swindow_system); 6130 defsubr (&Swindow_system);
diff --git a/src/fringe.c b/src/fringe.c
index 74f41f00873..335a6eb0468 100644
--- a/src/fringe.c
+++ b/src/fringe.c
@@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
30#include "buffer.h" 30#include "buffer.h"
31#include "blockinput.h" 31#include "blockinput.h"
32#include "termhooks.h" 32#include "termhooks.h"
33#include "pdumper.h"
33 34
34/* Fringe bitmaps are represented in three different ways: 35/* Fringe bitmaps are represented in three different ways:
35 36
@@ -1739,12 +1740,18 @@ mark_fringe_data (void)
1739 1740
1740/* Initialize this module when Emacs starts. */ 1741/* Initialize this module when Emacs starts. */
1741 1742
1743static void init_fringe_once_for_pdumper (void);
1744
1742void 1745void
1743init_fringe_once (void) 1746init_fringe_once (void)
1744{ 1747{
1745 int bt; 1748 pdumper_do_now_and_after_load (init_fringe_once_for_pdumper);
1749}
1746 1750
1747 for (bt = NO_FRINGE_BITMAP + 1; bt < MAX_STANDARD_FRINGE_BITMAPS; bt++) 1751static void
1752init_fringe_once_for_pdumper (void)
1753{
1754 for (int bt = NO_FRINGE_BITMAP + 1; bt < MAX_STANDARD_FRINGE_BITMAPS; bt++)
1748 init_fringe_bitmap (bt, &standard_bitmaps[bt], 1); 1755 init_fringe_bitmap (bt, &standard_bitmaps[bt], 1);
1749} 1756}
1750 1757
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index 314fa5b400d..7c18e04b743 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -26,6 +26,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
26#include "blockinput.h" 26#include "blockinput.h"
27#include "font.h" 27#include "font.h"
28#include "ftfont.h" 28#include "ftfont.h"
29#include "pdumper.h"
29 30
30/* FTCR font driver. */ 31/* FTCR font driver. */
31 32
@@ -282,6 +283,8 @@ ftcrfont_draw (struct glyph_string *s,
282 283
283 284
284 285
286static void syms_of_ftcrfont_for_pdumper (void);
287
285struct font_driver const ftcrfont_driver = 288struct font_driver const ftcrfont_driver =
286 { 289 {
287 .type = LISPSYM_INITIALLY (Qftcr), 290 .type = LISPSYM_INITIALLY (Qftcr),
@@ -317,5 +320,11 @@ syms_of_ftcrfont (void)
317 abort (); 320 abort ();
318 321
319 DEFSYM (Qftcr, "ftcr"); 322 DEFSYM (Qftcr, "ftcr");
323 pdumper_do_now_and_after_load (syms_of_ftcrfont_for_pdumper);
324}
325
326static void
327syms_of_ftcrfont_for_pdumper (void)
328{
320 register_font_driver (&ftcrfont_driver, NULL); 329 register_font_driver (&ftcrfont_driver, NULL);
321} 330}
diff --git a/src/ftfont.c b/src/ftfont.c
index f5a225be056..bcc3460cb74 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -34,6 +34,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
34#include "composite.h" 34#include "composite.h"
35#include "font.h" 35#include "font.h"
36#include "ftfont.h" 36#include "ftfont.h"
37#include "pdumper.h"
37 38
38static struct font_driver const ftfont_driver; 39static struct font_driver const ftfont_driver;
39 40
@@ -2701,6 +2702,8 @@ ftfont_combining_capability (struct font *font)
2701#endif 2702#endif
2702} 2703}
2703 2704
2705static void syms_of_ftfont_for_pdumper (void);
2706
2704static struct font_driver const ftfont_driver = 2707static struct font_driver const ftfont_driver =
2705 { 2708 {
2706 /* We can't draw a text without device dependent functions. */ 2709 /* We can't draw a text without device dependent functions. */
@@ -2752,5 +2755,12 @@ syms_of_ftfont (void)
2752 staticpro (&ft_face_cache); 2755 staticpro (&ft_face_cache);
2753 ft_face_cache = Qnil; 2756 ft_face_cache = Qnil;
2754 2757
2758 pdumper_do_now_and_after_load (syms_of_ftfont_for_pdumper);
2759}
2760
2761static void
2762syms_of_ftfont_for_pdumper (void)
2763{
2764 PDUMPER_RESET_LV (ft_face_cache, Qnil);
2755 register_font_driver (&ftfont_driver, NULL); 2765 register_font_driver (&ftfont_driver, NULL);
2756} 2766}
diff --git a/src/ftxfont.c b/src/ftxfont.c
index 726e0a845b1..f9a69c35151 100644
--- a/src/ftxfont.c
+++ b/src/ftxfont.c
@@ -28,6 +28,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
28#include "frame.h" 28#include "frame.h"
29#include "blockinput.h" 29#include "blockinput.h"
30#include "font.h" 30#include "font.h"
31#include "pdumper.h"
31 32
32/* FTX font driver. */ 33/* FTX font driver. */
33 34
@@ -339,6 +340,8 @@ ftxfont_end_for_frame (struct frame *f)
339 340
340 341
341 342
343static void syms_of_ftxfont_for_pdumper (void);
344
342struct font_driver const ftxfont_driver = 345struct font_driver const ftxfont_driver =
343 { 346 {
344 /* We can't draw a text without device dependent functions. */ 347 /* We can't draw a text without device dependent functions. */
@@ -373,5 +376,11 @@ void
373syms_of_ftxfont (void) 376syms_of_ftxfont (void)
374{ 377{
375 DEFSYM (Qftx, "ftx"); 378 DEFSYM (Qftx, "ftx");
379 pdumper_do_now_and_after_load (syms_of_ftxfont_for_pdumper);
380}
381
382static void
383syms_of_ftxfont_for_pdumper (void)
384{
376 register_font_driver (&ftxfont_driver, NULL); 385 register_font_driver (&ftxfont_driver, NULL);
377} 386}
diff --git a/src/gmalloc.c b/src/gmalloc.c
index c19885d9f80..b6a96d55727 100644
--- a/src/gmalloc.c
+++ b/src/gmalloc.c
@@ -76,7 +76,6 @@ extern void *(*__morecore) (ptrdiff_t);
76 76
77#ifdef HYBRID_MALLOC 77#ifdef HYBRID_MALLOC
78# include "sheap.h" 78# include "sheap.h"
79# define DUMPED bss_sbrk_did_unexec
80#endif 79#endif
81 80
82#ifdef __cplusplus 81#ifdef __cplusplus
@@ -1508,7 +1507,7 @@ static void *
1508gdefault_morecore (ptrdiff_t increment) 1507gdefault_morecore (ptrdiff_t increment)
1509{ 1508{
1510#ifdef HYBRID_MALLOC 1509#ifdef HYBRID_MALLOC
1511 if (!DUMPED) 1510 if (!definitely_will_not_unexec_p ())
1512 { 1511 {
1513 return bss_sbrk (increment); 1512 return bss_sbrk (increment);
1514 } 1513 }
@@ -1726,6 +1725,8 @@ extern int posix_memalign (void **memptr, size_t alignment, size_t size);
1726static bool 1725static bool
1727allocated_via_gmalloc (void *ptr) 1726allocated_via_gmalloc (void *ptr)
1728{ 1727{
1728 if (!__malloc_initialized)
1729 return false;
1729 size_t block = BLOCK (ptr); 1730 size_t block = BLOCK (ptr);
1730 size_t blockmax = _heaplimit - 1; 1731 size_t blockmax = _heaplimit - 1;
1731 return block <= blockmax && _heapinfo[block].busy.type != 0; 1732 return block <= blockmax && _heapinfo[block].busy.type != 0;
@@ -1737,7 +1738,7 @@ allocated_via_gmalloc (void *ptr)
1737void * 1738void *
1738hybrid_malloc (size_t size) 1739hybrid_malloc (size_t size)
1739{ 1740{
1740 if (DUMPED) 1741 if (definitely_will_not_unexec_p ())
1741 return malloc (size); 1742 return malloc (size);
1742 return gmalloc (size); 1743 return gmalloc (size);
1743} 1744}
@@ -1745,7 +1746,7 @@ hybrid_malloc (size_t size)
1745void * 1746void *
1746hybrid_calloc (size_t nmemb, size_t size) 1747hybrid_calloc (size_t nmemb, size_t size)
1747{ 1748{
1748 if (DUMPED) 1749 if (definitely_will_not_unexec_p ())
1749 return calloc (nmemb, size); 1750 return calloc (nmemb, size);
1750 return gcalloc (nmemb, size); 1751 return gcalloc (nmemb, size);
1751} 1752}
@@ -1763,7 +1764,7 @@ hybrid_free (void *ptr)
1763void * 1764void *
1764hybrid_aligned_alloc (size_t alignment, size_t size) 1765hybrid_aligned_alloc (size_t alignment, size_t size)
1765{ 1766{
1766 if (!DUMPED) 1767 if (!definitely_will_not_unexec_p ())
1767 return galigned_alloc (alignment, size); 1768 return galigned_alloc (alignment, size);
1768 /* The following is copied from alloc.c */ 1769 /* The following is copied from alloc.c */
1769#ifdef HAVE_ALIGNED_ALLOC 1770#ifdef HAVE_ALIGNED_ALLOC
@@ -1786,7 +1787,7 @@ hybrid_realloc (void *ptr, size_t size)
1786 return hybrid_malloc (size); 1787 return hybrid_malloc (size);
1787 if (!allocated_via_gmalloc (ptr)) 1788 if (!allocated_via_gmalloc (ptr))
1788 return realloc (ptr, size); 1789 return realloc (ptr, size);
1789 if (!DUMPED) 1790 if (!definitely_will_not_unexec_p ())
1790 return grealloc (ptr, size); 1791 return grealloc (ptr, size);
1791 1792
1792 /* The dumped emacs is trying to realloc storage allocated before 1793 /* The dumped emacs is trying to realloc storage allocated before
diff --git a/src/gnutls.c b/src/gnutls.c
index 1fe20d7ce2d..d0cb28dc536 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -25,6 +25,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
25#include "gnutls.h" 25#include "gnutls.h"
26#include "coding.h" 26#include "coding.h"
27#include "buffer.h" 27#include "buffer.h"
28#include "pdumper.h"
28 29
29#if GNUTLS_VERSION_NUMBER >= 0x030014 30#if GNUTLS_VERSION_NUMBER >= 0x030014
30# define HAVE_GNUTLS_X509_SYSTEM_TRUST 31# define HAVE_GNUTLS_X509_SYSTEM_TRUST
@@ -2626,6 +2627,7 @@ syms_of_gnutls (void)
2626 ); 2627 );
2627#ifdef HAVE_GNUTLS 2628#ifdef HAVE_GNUTLS
2628 gnutls_global_initialized = 0; 2629 gnutls_global_initialized = 0;
2630 PDUMPER_IGNORE (gnutls_global_initialized);
2629 2631
2630 DEFSYM (Qgnutls_code, "gnutls-code"); 2632 DEFSYM (Qgnutls_code, "gnutls-code");
2631 DEFSYM (Qgnutls_anon, "gnutls-anon"); 2633 DEFSYM (Qgnutls_anon, "gnutls-anon");
diff --git a/src/image.c b/src/image.c
index 2fae105815d..2f0b63ca899 100644
--- a/src/image.c
+++ b/src/image.c
@@ -46,6 +46,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
46#include "coding.h" 46#include "coding.h"
47#include "termhooks.h" 47#include "termhooks.h"
48#include "font.h" 48#include "font.h"
49#include "pdumper.h"
49 50
50#ifdef HAVE_SYS_STAT_H 51#ifdef HAVE_SYS_STAT_H
51#include <sys/stat.h> 52#include <sys/stat.h>
@@ -10003,7 +10004,9 @@ void
10003syms_of_image (void) 10004syms_of_image (void)
10004{ 10005{
10005 /* Initialize this only once; it will be reset before dumping. */ 10006 /* Initialize this only once; it will be reset before dumping. */
10007 /* The portable dumper will just leave it NULL, so no need to reset. */
10006 image_types = NULL; 10008 image_types = NULL;
10009 PDUMPER_IGNORE (image_types);
10007 10010
10008 /* Must be defined now because we're going to update it below, while 10011 /* Must be defined now because we're going to update it below, while
10009 defining the supported image types. */ 10012 defining the supported image types. */
diff --git a/src/insdel.c b/src/insdel.c
index 08f04d3ddca..a6f006a521d 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -29,6 +29,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
29#include "buffer.h" 29#include "buffer.h"
30#include "window.h" 30#include "window.h"
31#include "region-cache.h" 31#include "region-cache.h"
32#include "pdumper.h"
32 33
33static void insert_from_string_1 (Lisp_Object, ptrdiff_t, ptrdiff_t, ptrdiff_t, 34static void insert_from_string_1 (Lisp_Object, ptrdiff_t, ptrdiff_t, ptrdiff_t,
34 ptrdiff_t, bool, bool); 35 ptrdiff_t, bool, bool);
@@ -1927,6 +1928,14 @@ prepare_to_modify_buffer_1 (ptrdiff_t start, ptrdiff_t end,
1927 if (!NILP (BVAR (current_buffer, read_only))) 1928 if (!NILP (BVAR (current_buffer, read_only)))
1928 Fbarf_if_buffer_read_only (temp); 1929 Fbarf_if_buffer_read_only (temp);
1929 1930
1931 /* If we're about to modify a buffer the contents of which come from
1932 a dump file, copy the contents to private storage first so we
1933 don't take a COW fault on the buffer text and keep it around
1934 forever. */
1935 if (pdumper_object_p (BEG_ADDR))
1936 enlarge_buffer_text (current_buffer, 0);
1937 eassert (!pdumper_object_p (BEG_ADDR));
1938
1930 run_undoable_change(); 1939 run_undoable_change();
1931 1940
1932 bset_redisplay (current_buffer); 1941 bset_redisplay (current_buffer);
diff --git a/src/intervals.h b/src/intervals.h
index 3cee7889414..9c5adf33a14 100644
--- a/src/intervals.h
+++ b/src/intervals.h
@@ -29,7 +29,6 @@ INLINE_HEADER_BEGIN
29struct interval 29struct interval
30{ 30{
31 /* The first group of entries deal with the tree structure. */ 31 /* The first group of entries deal with the tree structure. */
32
33 ptrdiff_t total_length; /* Length of myself and both children. */ 32 ptrdiff_t total_length; /* Length of myself and both children. */
34 ptrdiff_t position; /* Cache of interval's character position. */ 33 ptrdiff_t position; /* Cache of interval's character position. */
35 /* This field is usually updated 34 /* This field is usually updated
diff --git a/src/keyboard.c b/src/keyboard.c
index 9e38bb21f6e..2d6fa91a16c 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -68,6 +68,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
68 68
69#include <ignore-value.h> 69#include <ignore-value.h>
70 70
71#include "pdumper.h"
72
71#ifdef HAVE_WINDOW_SYSTEM 73#ifdef HAVE_WINDOW_SYSTEM
72#include TERM_HEADER 74#include TERM_HEADER
73#endif /* HAVE_WINDOW_SYSTEM */ 75#endif /* HAVE_WINDOW_SYSTEM */
@@ -10977,6 +10979,8 @@ static const struct event_head head_table[] = {
10977 {SYMBOL_INDEX (Qselect_window), SYMBOL_INDEX (Qswitch_frame)} 10979 {SYMBOL_INDEX (Qselect_window), SYMBOL_INDEX (Qswitch_frame)}
10978}; 10980};
10979 10981
10982static void syms_of_keyboard_for_pdumper (void);
10983
10980void 10984void
10981syms_of_keyboard (void) 10985syms_of_keyboard (void)
10982{ 10986{
@@ -10987,9 +10991,11 @@ syms_of_keyboard (void)
10987 staticpro (&Vlispy_mouse_stem); 10991 staticpro (&Vlispy_mouse_stem);
10988 10992
10989 regular_top_level_message = build_pure_c_string ("Back to top level"); 10993 regular_top_level_message = build_pure_c_string ("Back to top level");
10994 staticpro (&regular_top_level_message);
10990#ifdef HAVE_STACK_OVERFLOW_HANDLING 10995#ifdef HAVE_STACK_OVERFLOW_HANDLING
10991 recover_top_level_message 10996 recover_top_level_message
10992 = build_pure_c_string ("Re-entering top level after C stack overflow"); 10997 = build_pure_c_string ("Re-entering top level after C stack overflow");
10998 staticpro (&recover_top_level_message);
10993#endif 10999#endif
10994 DEFVAR_LISP ("internal--top-level-message", Vinternal__top_level_message, 11000 DEFVAR_LISP ("internal--top-level-message", Vinternal__top_level_message,
10995 doc: /* Message displayed by `normal-top-level'. */); 11001 doc: /* Message displayed by `normal-top-level'. */);
@@ -11828,7 +11834,38 @@ preserve data in modified buffers that would otherwise be lost.
11828If nil, Emacs crashes immediately in response to fatal signals. */); 11834If nil, Emacs crashes immediately in response to fatal signals. */);
11829 attempt_orderly_shutdown_on_fatal_signal = true; 11835 attempt_orderly_shutdown_on_fatal_signal = true;
11830 11836
11837 pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
11838}
11839
11840static void
11841syms_of_keyboard_for_pdumper (void)
11842{
11843 /* Make sure input state is pristine when restoring from a dump.
11844 init_keyboard() also resets some of these, but the duplication
11845 doesn't hurt and makes sure that allocate_kboard and subsequent
11846 early init functions see the environment they expect. */
11847
11848 PDUMPER_RESET_LV (pending_funcalls, Qnil);
11849 PDUMPER_RESET_LV (unread_switch_frame, Qnil);
11850 PDUMPER_RESET_LV (internal_last_event_frame, Qnil);
11851 PDUMPER_RESET_LV (last_command_event, Qnil);
11852 PDUMPER_RESET_LV (last_nonmenu_event, Qnil);
11853 PDUMPER_RESET_LV (last_input_event, Qnil);
11854 PDUMPER_RESET_LV (Vunread_command_events, Qnil);
11855 PDUMPER_RESET_LV (Vunread_post_input_method_events, Qnil);
11856 PDUMPER_RESET_LV (Vunread_input_method_events, Qnil);
11857 PDUMPER_RESET_LV (Vthis_command, Qnil);
11858 PDUMPER_RESET_LV (Vreal_this_command, Qnil);
11859 PDUMPER_RESET_LV (Vthis_command_keys_shift_translated, Qnil);
11860 PDUMPER_RESET_LV (Vthis_original_command, Qnil);
11861 PDUMPER_RESET (num_input_keys, 0);
11862 PDUMPER_RESET (num_nonmacro_input_events, 0);
11863 PDUMPER_RESET_LV (Vlast_event_frame, Qnil);
11864 PDUMPER_RESET_LV (Vdeferred_action_list, Qnil);
11865 PDUMPER_RESET_LV (Vdelayed_warnings_list, Qnil);
11866
11831 /* Create the initial keyboard. Qt means 'unset'. */ 11867 /* Create the initial keyboard. Qt means 'unset'. */
11868 eassert (initial_kboard == NULL);
11832 initial_kboard = allocate_kboard (Qt); 11869 initial_kboard = allocate_kboard (Qt);
11833 11870
11834 DEFVAR_LISP ("while-no-input-ignore-events", 11871 DEFVAR_LISP ("while-no-input-ignore-events",
@@ -11940,8 +11977,8 @@ mark_kboards (void)
11940 for (kb = all_kboards; kb; kb = kb->next_kboard) 11977 for (kb = all_kboards; kb; kb = kb->next_kboard)
11941 { 11978 {
11942 if (kb->kbd_macro_buffer) 11979 if (kb->kbd_macro_buffer)
11943 for (p = kb->kbd_macro_buffer; p < kb->kbd_macro_ptr; p++) 11980 for (p = kb->kbd_macro_buffer; p < kb->kbd_macro_ptr; p++)
11944 mark_object (*p); 11981 mark_object (*p);
11945 mark_object (KVAR (kb, Voverriding_terminal_local_map)); 11982 mark_object (KVAR (kb, Voverriding_terminal_local_map));
11946 mark_object (KVAR (kb, Vlast_command)); 11983 mark_object (KVAR (kb, Vlast_command));
11947 mark_object (KVAR (kb, Vreal_last_command)); 11984 mark_object (KVAR (kb, Vreal_last_command));
diff --git a/src/lisp.h b/src/lisp.h
index faf5a4ad407..5c48905232f 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -527,6 +527,7 @@ enum Lisp_Type
527 /* Cons. XCONS (object) points to a struct Lisp_Cons. */ 527 /* Cons. XCONS (object) points to a struct Lisp_Cons. */
528 Lisp_Cons = USE_LSB_TAG ? 3 : 6, 528 Lisp_Cons = USE_LSB_TAG ? 3 : 6,
529 529
530 /* Must be last entry in Lisp_Type enumeration. */
530 Lisp_Float = 7 531 Lisp_Float = 7
531 }; 532 };
532 533
@@ -623,16 +624,110 @@ extern void char_table_set (Lisp_Object, int, Lisp_Object);
623extern _Noreturn void wrong_type_argument (Lisp_Object, Lisp_Object); 624extern _Noreturn void wrong_type_argument (Lisp_Object, Lisp_Object);
624 625
625 626
626#ifdef CANNOT_DUMP
627enum { might_dump = false };
628#elif defined DOUG_LEA_MALLOC
629/* Defined in emacs.c. */ 627/* Defined in emacs.c. */
630extern bool might_dump; 628
631#endif 629/* Set after Emacs has started up the first time.
632/* True means Emacs has already been initialized. 630 Prevents reinitialization of the Lisp world and keymaps on
633 Used during startup to detect startup of dumped Emacs. */ 631 subsequent starts. */
634extern bool initialized; 632extern bool initialized;
635 633
634extern struct gflags {
635 /* True means this Emacs instance was born to dump. */
636#if defined (HAVE_PDUMPER) || !defined (CANNOT_DUMP)
637 bool will_dump_ : 1;
638 bool will_bootstrap_ : 1;
639#endif
640#if defined (HAVE_PDUMPER)
641 /* Set in an Emacs process that will likely dump with pdumper; all
642 Emacs processes may dump with pdumper, however. */
643 bool will_dump_with_pdumper_ : 1;
644 /* Set in an Emacs process that has been restored from a portable
645 dump. */
646 bool dumped_with_pdumper_ : 1;
647#endif
648#ifndef CANNOT_DUMP
649 bool will_dump_with_unexec_ : 1;
650 /* Set in an Emacs process that has been restored from an unexec
651 dump. */
652 bool dumped_with_unexec_ : 1;
653 /* We promise not to unexec: useful for hybrid malloc. */
654 bool will_not_unexec_ : 1;
655#endif
656} gflags;
657
658INLINE bool
659will_dump_p (void)
660{
661#if HAVE_PDUMPER || !defined (CANNOT_DUMP)
662 return gflags.will_dump_;
663#else
664 return false;
665#endif
666}
667
668INLINE bool
669will_bootstrap_p (void)
670{
671#if HAVE_PDUMPER || !defined (CANNOT_DUMP)
672 return gflags.will_bootstrap_;
673#else
674 return false;
675#endif
676}
677
678INLINE bool
679will_dump_with_pdumper_p (void)
680{
681#if HAVE_PDUMPER
682 return gflags.will_dump_with_pdumper_;
683#else
684 return false;
685#endif
686}
687
688INLINE bool
689dumped_with_pdumper_p (void)
690{
691#if HAVE_PDUMPER
692 return gflags.dumped_with_pdumper_;
693#else
694 return false;
695#endif
696}
697
698INLINE bool
699will_dump_with_unexec_p (void)
700{
701#ifdef CANNOT_DUMP
702 return false;
703#else
704 return gflags.will_dump_with_unexec_;
705#endif
706}
707
708INLINE bool
709dumped_with_unexec_p (void)
710{
711#ifdef CANNOT_DUMP
712 return false;
713#else
714 return gflags.dumped_with_unexec_;
715#endif
716}
717
718/* This function is the opposite of will_dump_with_unexec_p(), except
719 that it returns false before main runs. It's important to use
720 gmalloc for any pre-main allocations if we're going to unexec. */
721INLINE bool
722definitely_will_not_unexec_p (void)
723{
724#ifdef CANNOT_DUMP
725 return true;
726#else
727 return gflags.will_not_unexec_;
728#endif
729}
730
636/* Defined in floatfns.c. */ 731/* Defined in floatfns.c. */
637extern double extract_float (Lisp_Object); 732extern double extract_float (Lisp_Object);
638 733
@@ -862,6 +957,19 @@ typedef EMACS_UINT Lisp_Word_tag;
862# define DEFINE_NON_NIL_Q_SYMBOL_MACROS true 957# define DEFINE_NON_NIL_Q_SYMBOL_MACROS true
863#endif 958#endif
864 959
960/* True if N is a power of 2. N should be positive. */
961
962#define POWER_OF_2(n) (((n) & ((n) - 1)) == 0)
963
964/* Return X rounded to the next multiple of Y. Y should be positive,
965 and Y - 1 + X should not overflow. Arguments should not have side
966 effects, as they are evaluated more than once. Tune for Y being a
967 power of 2. */
968
969#define ROUNDUP(x, y) (POWER_OF_2 (y) \
970 ? ((y) - 1 + (x)) & ~ ((y) - 1) \
971 : ((y) - 1 + (x)) - ((y) - 1 + (x)) % (y))
972
865#include "globals.h" 973#include "globals.h"
866 974
867/* Header of vector-like objects. This documents the layout constraints on 975/* Header of vector-like objects. This documents the layout constraints on
@@ -1568,7 +1676,7 @@ CHECK_VECTOR (Lisp_Object x)
1568/* A pseudovector is like a vector, but has other non-Lisp components. */ 1676/* A pseudovector is like a vector, but has other non-Lisp components. */
1569 1677
1570INLINE enum pvec_type 1678INLINE enum pvec_type
1571PSEUDOVECTOR_TYPE (struct Lisp_Vector *v) 1679PSEUDOVECTOR_TYPE (const struct Lisp_Vector *v)
1572{ 1680{
1573 ptrdiff_t size = v->header.size; 1681 ptrdiff_t size = v->header.size;
1574 return (size & PSEUDOVECTOR_FLAG 1682 return (size & PSEUDOVECTOR_FLAG
@@ -1578,7 +1686,7 @@ PSEUDOVECTOR_TYPE (struct Lisp_Vector *v)
1578 1686
1579/* Can't be used with PVEC_NORMAL_VECTOR. */ 1687/* Can't be used with PVEC_NORMAL_VECTOR. */
1580INLINE bool 1688INLINE bool
1581PSEUDOVECTOR_TYPEP (union vectorlike_header *a, enum pvec_type code) 1689PSEUDOVECTOR_TYPEP (const union vectorlike_header *a, enum pvec_type code)
1582{ 1690{
1583 /* We don't use PSEUDOVECTOR_TYPE here so as to avoid a shift 1691 /* We don't use PSEUDOVECTOR_TYPE here so as to avoid a shift
1584 * operation when `code' is known. */ 1692 * operation when `code' is known. */
@@ -2168,6 +2276,12 @@ struct hash_table_test
2168 2276
2169struct Lisp_Hash_Table 2277struct Lisp_Hash_Table
2170{ 2278{
2279 /* Change pdumper.c if you change the fields here.
2280
2281 IMPORTANT!!!!!!!
2282
2283 Call hash_rehash_if_needed() before accessing. */
2284
2171 /* This is for Lisp; the hash table code does not refer to it. */ 2285 /* This is for Lisp; the hash table code does not refer to it. */
2172 union vectorlike_header header; 2286 union vectorlike_header header;
2173 2287
@@ -2224,8 +2338,9 @@ struct Lisp_Hash_Table
2224 /* The comparison and hash functions. */ 2338 /* The comparison and hash functions. */
2225 struct hash_table_test test; 2339 struct hash_table_test test;
2226 2340
2227 /* Next weak hash table if this is a weak hash table. The head 2341 /* Next weak hash table if this is a weak hash table. The head of
2228 of the list is in weak_hash_tables. */ 2342 the list is in weak_hash_tables. Used only during garbage
2343 collection --- at other times, it is NULL. */
2229 struct Lisp_Hash_Table *next_weak; 2344 struct Lisp_Hash_Table *next_weak;
2230} GCALIGNED_STRUCT; 2345} GCALIGNED_STRUCT;
2231 2346
@@ -2250,32 +2365,47 @@ XHASH_TABLE (Lisp_Object a)
2250 2365
2251/* Value is the key part of entry IDX in hash table H. */ 2366/* Value is the key part of entry IDX in hash table H. */
2252INLINE Lisp_Object 2367INLINE Lisp_Object
2253HASH_KEY (struct Lisp_Hash_Table *h, ptrdiff_t idx) 2368HASH_KEY (const struct Lisp_Hash_Table *h, ptrdiff_t idx)
2254{ 2369{
2255 return AREF (h->key_and_value, 2 * idx); 2370 return AREF (h->key_and_value, 2 * idx);
2256} 2371}
2257 2372
2258/* Value is the value part of entry IDX in hash table H. */ 2373/* Value is the value part of entry IDX in hash table H. */
2259INLINE Lisp_Object 2374INLINE Lisp_Object
2260HASH_VALUE (struct Lisp_Hash_Table *h, ptrdiff_t idx) 2375HASH_VALUE (const struct Lisp_Hash_Table *h, ptrdiff_t idx)
2261{ 2376{
2262 return AREF (h->key_and_value, 2 * idx + 1); 2377 return AREF (h->key_and_value, 2 * idx + 1);
2263} 2378}
2264 2379
2265/* Value is the hash code computed for entry IDX in hash table H. */ 2380/* Value is the hash code computed for entry IDX in hash table H. */
2266INLINE Lisp_Object 2381INLINE Lisp_Object
2267HASH_HASH (struct Lisp_Hash_Table *h, ptrdiff_t idx) 2382HASH_HASH (const struct Lisp_Hash_Table *h, ptrdiff_t idx)
2268{ 2383{
2269 return AREF (h->hash, idx); 2384 return AREF (h->hash, idx);
2270} 2385}
2271 2386
2272/* Value is the size of hash table H. */ 2387/* Value is the size of hash table H. */
2273INLINE ptrdiff_t 2388INLINE ptrdiff_t
2274HASH_TABLE_SIZE (struct Lisp_Hash_Table *h) 2389HASH_TABLE_SIZE (const struct Lisp_Hash_Table *h)
2275{ 2390{
2276 return ASIZE (h->next); 2391 return ASIZE (h->next);
2277} 2392}
2278 2393
2394void hash_table_rehash (struct Lisp_Hash_Table *h);
2395
2396INLINE bool
2397hash_rehash_needed_p (const struct Lisp_Hash_Table *h)
2398{
2399 return h->count < 0;
2400}
2401
2402INLINE void
2403hash_rehash_if_needed (struct Lisp_Hash_Table *h)
2404{
2405 if (hash_rehash_needed_p (h))
2406 hash_table_rehash (h);
2407}
2408
2279/* Default size for hash tables if not specified. */ 2409/* Default size for hash tables if not specified. */
2280 2410
2281enum DEFAULT_HASH_SIZE { DEFAULT_HASH_SIZE = 65 }; 2411enum DEFAULT_HASH_SIZE { DEFAULT_HASH_SIZE = 65 };
@@ -2441,6 +2571,9 @@ struct Lisp_Finalizer
2441 struct Lisp_Finalizer *next; 2571 struct Lisp_Finalizer *next;
2442 } GCALIGNED_STRUCT; 2572 } GCALIGNED_STRUCT;
2443 2573
2574extern struct Lisp_Finalizer finalizers;
2575extern struct Lisp_Finalizer doomed_finalizers;
2576
2444INLINE bool 2577INLINE bool
2445FINALIZERP (Lisp_Object x) 2578FINALIZERP (Lisp_Object x)
2446{ 2579{
@@ -2895,6 +3028,20 @@ CHECK_INTEGER (Lisp_Object x)
2895 CHECK_TYPE (INTEGERP (x), Qnumber_or_marker_p, x); \ 3028 CHECK_TYPE (INTEGERP (x), Qnumber_or_marker_p, x); \
2896 } while (false) 3029 } while (false)
2897 3030
3031
3032/* If we're not dumping using the legacy dumper and we might be using
3033 the portable dumper, try to bunch all the subr structures together
3034 for more efficient dump loading. */
3035#ifdef CANNOT_DUMP
3036# ifdef DARWIN_OS
3037# define SUBR_SECTION_ATTRIBUTE ATTRIBUTE_SECTION ("__DATA,subrs")
3038# else
3039# define SUBR_SECTION_ATTRIBUTE ATTRIBUTE_SECTION (".subrs")
3040# endif
3041#else
3042# define SUBR_SECTION_ATTRIBUTE
3043#endif
3044
2898/* Define a built-in function for calling from Lisp. 3045/* Define a built-in function for calling from Lisp.
2899 `lname' should be the name to give the function in Lisp, 3046 `lname' should be the name to give the function in Lisp,
2900 as a null-terminated C string. 3047 as a null-terminated C string.
@@ -2923,7 +3070,8 @@ CHECK_INTEGER (Lisp_Object x)
2923/* This version of DEFUN declares a function prototype with the right 3070/* This version of DEFUN declares a function prototype with the right
2924 arguments, so we can catch errors with maxargs at compile-time. */ 3071 arguments, so we can catch errors with maxargs at compile-time. */
2925#define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc) \ 3072#define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc) \
2926 static union Aligned_Lisp_Subr sname = \ 3073 SUBR_SECTION_ATTRIBUTE \
3074 static union Aligned_Lisp_Subr sname = \
2927 {{{ PVEC_SUBR << PSEUDOVECTOR_AREA_BITS }, \ 3075 {{{ PVEC_SUBR << PSEUDOVECTOR_AREA_BITS }, \
2928 { .a ## maxargs = fnname }, \ 3076 { .a ## maxargs = fnname }, \
2929 minargs, maxargs, lname, intspec, 0}}; \ 3077 minargs, maxargs, lname, intspec, 0}}; \
@@ -3169,6 +3317,11 @@ extern Lisp_Object Vascii_canon_table;
3169/* Call staticpro (&var) to protect static variable `var'. */ 3317/* Call staticpro (&var) to protect static variable `var'. */
3170 3318
3171void staticpro (Lisp_Object *); 3319void staticpro (Lisp_Object *);
3320
3321enum { NSTATICS = 2048 };
3322extern Lisp_Object *staticvec[NSTATICS];
3323extern int staticidx;
3324
3172 3325
3173/* Forward declarations for prototypes. */ 3326/* Forward declarations for prototypes. */
3174struct window; 3327struct window;
@@ -3416,12 +3569,14 @@ enum { NEXT_ALMOST_PRIME_LIMIT = 11 };
3416extern ptrdiff_t list_length (Lisp_Object); 3569extern ptrdiff_t list_length (Lisp_Object);
3417extern EMACS_INT next_almost_prime (EMACS_INT) ATTRIBUTE_CONST; 3570extern EMACS_INT next_almost_prime (EMACS_INT) ATTRIBUTE_CONST;
3418extern Lisp_Object larger_vector (Lisp_Object, ptrdiff_t, ptrdiff_t); 3571extern Lisp_Object larger_vector (Lisp_Object, ptrdiff_t, ptrdiff_t);
3419extern void sweep_weak_hash_tables (void); 3572extern bool sweep_weak_table (struct Lisp_Hash_Table *, bool);
3420extern char *extract_data_from_object (Lisp_Object, ptrdiff_t *, ptrdiff_t *); 3573extern char *extract_data_from_object (Lisp_Object, ptrdiff_t *, ptrdiff_t *);
3421EMACS_UINT hash_string (char const *, ptrdiff_t); 3574EMACS_UINT hash_string (char const *, ptrdiff_t);
3422EMACS_UINT sxhash (Lisp_Object, int); 3575EMACS_UINT sxhash (Lisp_Object, int);
3576EMACS_UINT hashfn_eql (struct hash_table_test *ht, Lisp_Object key);
3577EMACS_UINT hashfn_equal (struct hash_table_test *ht, Lisp_Object key);
3423Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float, 3578Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float,
3424 Lisp_Object, bool); 3579 Lisp_Object, bool);
3425ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, EMACS_UINT *); 3580ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, EMACS_UINT *);
3426ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object, 3581ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
3427 EMACS_UINT); 3582 EMACS_UINT);
@@ -3592,6 +3747,12 @@ typedef uintptr_t byte_ct; /* System byte counts reported by GC. */
3592extern byte_ct consing_since_gc; 3747extern byte_ct consing_since_gc;
3593extern byte_ct gc_relative_threshold; 3748extern byte_ct gc_relative_threshold;
3594extern byte_ct memory_full_cons_threshold; 3749extern byte_ct memory_full_cons_threshold;
3750#ifdef HAVE_PDUMPER
3751extern int number_finalizers_run;
3752#endif
3753#ifdef ENABLE_CHECKING
3754extern Lisp_Object Vdead;
3755#endif
3595extern Lisp_Object list1 (Lisp_Object); 3756extern Lisp_Object list1 (Lisp_Object);
3596extern Lisp_Object list2 (Lisp_Object, Lisp_Object); 3757extern Lisp_Object list2 (Lisp_Object, Lisp_Object);
3597extern Lisp_Object list3 (Lisp_Object, Lisp_Object, Lisp_Object); 3758extern Lisp_Object list3 (Lisp_Object, Lisp_Object, Lisp_Object);
@@ -3601,6 +3762,21 @@ extern Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object,
3601enum constype {CONSTYPE_HEAP, CONSTYPE_PURE}; 3762enum constype {CONSTYPE_HEAP, CONSTYPE_PURE};
3602extern Lisp_Object listn (enum constype, ptrdiff_t, Lisp_Object, ...); 3763extern Lisp_Object listn (enum constype, ptrdiff_t, Lisp_Object, ...);
3603 3764
3765enum gc_root_type {
3766 GC_ROOT_STATICPRO,
3767 GC_ROOT_BUFFER_LOCAL_DEFAULT,
3768 GC_ROOT_BUFFER_LOCAL_NAME,
3769 GC_ROOT_C_SYMBOL
3770};
3771
3772struct gc_root_visitor {
3773 void (*visit)(Lisp_Object *root_ptr,
3774 enum gc_root_type type,
3775 void *data);
3776 void *data;
3777};
3778extern void visit_static_gc_roots (struct gc_root_visitor visitor);
3779
3604/* Build a frequently used 2/3/4-integer lists. */ 3780/* Build a frequently used 2/3/4-integer lists. */
3605 3781
3606INLINE Lisp_Object 3782INLINE Lisp_Object
@@ -3629,6 +3805,13 @@ extern Lisp_Object make_string (const char *, ptrdiff_t);
3629extern Lisp_Object make_formatted_string (char *, const char *, ...) 3805extern Lisp_Object make_formatted_string (char *, const char *, ...)
3630 ATTRIBUTE_FORMAT_PRINTF (2, 3); 3806 ATTRIBUTE_FORMAT_PRINTF (2, 3);
3631extern Lisp_Object make_unibyte_string (const char *, ptrdiff_t); 3807extern Lisp_Object make_unibyte_string (const char *, ptrdiff_t);
3808extern ptrdiff_t vectorlike_nbytes (const union vectorlike_header *hdr);
3809
3810INLINE ptrdiff_t
3811vector_nbytes (const struct Lisp_Vector *v)
3812{
3813 return vectorlike_nbytes (&v->header);
3814}
3632 3815
3633/* Make unibyte string from C string when the length isn't known. */ 3816/* Make unibyte string from C string when the length isn't known. */
3634 3817
@@ -3824,7 +4007,7 @@ extern Lisp_Object string_to_number (char const *, int, ptrdiff_t *);
3824extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), 4007extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object),
3825 Lisp_Object); 4008 Lisp_Object);
3826extern void dir_warning (const char *, Lisp_Object); 4009extern void dir_warning (const char *, Lisp_Object);
3827extern void init_obarray (void); 4010extern void init_obarray_once (void);
3828extern void init_lread (void); 4011extern void init_lread (void);
3829extern void syms_of_lread (void); 4012extern void syms_of_lread (void);
3830 4013
@@ -3989,6 +4172,7 @@ extern void syms_of_module (void);
3989#endif 4172#endif
3990 4173
3991/* Defined in thread.c. */ 4174/* Defined in thread.c. */
4175extern struct thread_state primary_thread;
3992extern void mark_threads (void); 4176extern void mark_threads (void);
3993extern void unmark_main_thread (void); 4177extern void unmark_main_thread (void);
3994 4178
@@ -4017,7 +4201,7 @@ extern bool overlay_touches_p (ptrdiff_t);
4017extern Lisp_Object other_buffer_safely (Lisp_Object); 4201extern Lisp_Object other_buffer_safely (Lisp_Object);
4018extern Lisp_Object get_truename_buffer (Lisp_Object); 4202extern Lisp_Object get_truename_buffer (Lisp_Object);
4019extern void init_buffer_once (void); 4203extern void init_buffer_once (void);
4020extern void init_buffer (int); 4204extern void init_buffer (void);
4021extern void syms_of_buffer (void); 4205extern void syms_of_buffer (void);
4022extern void keys_of_buffer (void); 4206extern void keys_of_buffer (void);
4023 4207
@@ -4160,6 +4344,7 @@ extern void store_in_alist (Lisp_Object *, Lisp_Object, Lisp_Object);
4160extern Lisp_Object do_switch_frame (Lisp_Object, int, int, Lisp_Object); 4344extern Lisp_Object do_switch_frame (Lisp_Object, int, int, Lisp_Object);
4161extern Lisp_Object get_frame_param (struct frame *, Lisp_Object); 4345extern Lisp_Object get_frame_param (struct frame *, Lisp_Object);
4162extern void frames_discard_buffer (Lisp_Object); 4346extern void frames_discard_buffer (Lisp_Object);
4347extern void init_frame_once (void);
4163extern void syms_of_frame (void); 4348extern void syms_of_frame (void);
4164 4349
4165/* Defined in emacs.c. */ 4350/* Defined in emacs.c. */
diff --git a/src/lread.c b/src/lread.c
index 5a595f2119b..dde9ccef549 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -42,6 +42,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
42#include "systime.h" 42#include "systime.h"
43#include "termhooks.h" 43#include "termhooks.h"
44#include "blockinput.h" 44#include "blockinput.h"
45#include "pdumper.h"
45#include <c-ctype.h> 46#include <c-ctype.h>
46 47
47#ifdef MSDOS 48#ifdef MSDOS
@@ -1969,7 +1970,7 @@ readevalloop (Lisp_Object readcharfun,
1969 ? Qnil : list1 (Qt))); 1970 ? Qnil : list1 (Qt)));
1970 1971
1971 /* Try to ensure sourcename is a truename, except whilst preloading. */ 1972 /* Try to ensure sourcename is a truename, except whilst preloading. */
1972 if (NILP (Vpurify_flag) 1973 if (!will_dump_p ()
1973 && !NILP (sourcename) && !NILP (Ffile_name_absolute_p (sourcename)) 1974 && !NILP (sourcename) && !NILP (Ffile_name_absolute_p (sourcename))
1974 && !NILP (Ffboundp (Qfile_truename))) 1975 && !NILP (Ffboundp (Qfile_truename)))
1975 sourcename = call1 (Qfile_truename, sourcename) ; 1976 sourcename = call1 (Qfile_truename, sourcename) ;
@@ -4373,7 +4374,7 @@ OBARRAY defaults to the value of `obarray'. */)
4373#define OBARRAY_SIZE 15121 4374#define OBARRAY_SIZE 15121
4374 4375
4375void 4376void
4376init_obarray (void) 4377init_obarray_once (void)
4377{ 4378{
4378 Vobarray = make_vector (OBARRAY_SIZE, make_fixnum (0)); 4379 Vobarray = make_vector (OBARRAY_SIZE, make_fixnum (0));
4379 initial_obarray = Vobarray; 4380 initial_obarray = Vobarray;
@@ -4394,12 +4395,15 @@ init_obarray (void)
4394 make_symbol_constant (Qt); 4395 make_symbol_constant (Qt);
4395 XSYMBOL (Qt)->u.s.declared_special = true; 4396 XSYMBOL (Qt)->u.s.declared_special = true;
4396 4397
4397 /* Qt is correct even if CANNOT_DUMP. loadup.el will set to nil at end. */ 4398 /* Qt is correct even if not dumping. loadup.el will set to nil at end. */
4398 Vpurify_flag = Qt; 4399 Vpurify_flag = Qt;
4399 4400
4400 DEFSYM (Qvariable_documentation, "variable-documentation"); 4401 DEFSYM (Qvariable_documentation, "variable-documentation");
4401} 4402}
4403
4402 4404
4405int ndefsubr;
4406
4403void 4407void
4404defsubr (union Aligned_Lisp_Subr *aname) 4408defsubr (union Aligned_Lisp_Subr *aname)
4405{ 4409{
@@ -4409,6 +4413,7 @@ defsubr (union Aligned_Lisp_Subr *aname)
4409 XSETPVECTYPE (sname, PVEC_SUBR); 4413 XSETPVECTYPE (sname, PVEC_SUBR);
4410 XSETSUBR (tem, sname); 4414 XSETSUBR (tem, sname);
4411 set_symbol_function (sym, tem); 4415 set_symbol_function (sym, tem);
4416 ++ndefsubr;
4412} 4417}
4413 4418
4414#ifdef NOTDEF /* Use fset in subr.el now! */ 4419#ifdef NOTDEF /* Use fset in subr.el now! */
@@ -4526,11 +4531,9 @@ load_path_check (Lisp_Object lpath)
4526 are running uninstalled. 4531 are running uninstalled.
4527 4532
4528 Uses the following logic: 4533 Uses the following logic:
4529 If CANNOT_DUMP: 4534 If !will_dump: Use PATH_LOADSEARCH.
4530 If Vinstallation_directory is not nil (ie, running uninstalled), 4535 The remainder is what happens when dumping is about to happen:
4531 use PATH_DUMPLOADSEARCH (ie, build path). Else use PATH_LOADSEARCH. 4536 If dumping, just use PATH_DUMPLOADSEARCH.
4532 The remainder is what happens when dumping works:
4533 If purify-flag (ie dumping) just use PATH_DUMPLOADSEARCH.
4534 Otherwise use PATH_LOADSEARCH. 4537 Otherwise use PATH_LOADSEARCH.
4535 4538
4536 If !initialized, then just return PATH_DUMPLOADSEARCH. 4539 If !initialized, then just return PATH_DUMPLOADSEARCH.
@@ -4553,131 +4556,109 @@ load_path_check (Lisp_Object lpath)
4553static Lisp_Object 4556static Lisp_Object
4554load_path_default (void) 4557load_path_default (void)
4555{ 4558{
4559 if (will_dump_p ())
4560 /* PATH_DUMPLOADSEARCH is the lisp dir in the source directory.
4561 We used to add ../lisp (ie the lisp dir in the build
4562 directory) at the front here, but that should not be
4563 necessary, since in out of tree builds lisp/ is empty, save
4564 for Makefile. */
4565 return decode_env_path (0, PATH_DUMPLOADSEARCH, 0);
4566
4556 Lisp_Object lpath = Qnil; 4567 Lisp_Object lpath = Qnil;
4557 const char *normal; 4568 const char *normal = PATH_LOADSEARCH;
4569 const char *loadpath = NULL;
4558 4570
4559#ifdef CANNOT_DUMP
4560#ifdef HAVE_NS 4571#ifdef HAVE_NS
4561 const char *loadpath = ns_load_path (); 4572 loadpath = ns_load_path ();
4562#endif 4573#endif
4563 4574
4564 normal = PATH_LOADSEARCH;
4565 if (!NILP (Vinstallation_directory)) normal = PATH_DUMPLOADSEARCH;
4566
4567#ifdef HAVE_NS
4568 lpath = decode_env_path (0, loadpath ? loadpath : normal, 0); 4575 lpath = decode_env_path (0, loadpath ? loadpath : normal, 0);
4569#else
4570 lpath = decode_env_path (0, normal, 0);
4571#endif
4572
4573#else /* !CANNOT_DUMP */
4574
4575 normal = NILP (Vpurify_flag) ? PATH_LOADSEARCH : PATH_DUMPLOADSEARCH;
4576 4576
4577 if (initialized) 4577 if (!NILP (Vinstallation_directory))
4578 { 4578 {
4579#ifdef HAVE_NS 4579 Lisp_Object tem, tem1;
4580 const char *loadpath = ns_load_path (); 4580
4581 lpath = decode_env_path (0, loadpath ? loadpath : normal, 0); 4581 /* Add to the path the lisp subdir of the installation
4582#else 4582 dir, if it is accessible. Note: in out-of-tree builds,
4583 lpath = decode_env_path (0, normal, 0); 4583 this directory is empty save for Makefile. */
4584#endif 4584 tem = Fexpand_file_name (build_string ("lisp"),
4585 if (!NILP (Vinstallation_directory)) 4585 Vinstallation_directory);
4586 tem1 = Ffile_accessible_directory_p (tem);
4587 if (!NILP (tem1))
4588 {
4589 if (NILP (Fmember (tem, lpath)))
4590 {
4591 /* We are running uninstalled. The default load-path
4592 points to the eventual installed lisp directories.
4593 We should not use those now, even if they exist,
4594 so start over from a clean slate. */
4595 lpath = list1 (tem);
4596 }
4597 }
4598 else
4599 /* That dir doesn't exist, so add the build-time
4600 Lisp dirs instead. */
4586 { 4601 {
4587 Lisp_Object tem, tem1; 4602 Lisp_Object dump_path =
4603 decode_env_path (0, PATH_DUMPLOADSEARCH, 0);
4604 lpath = nconc2 (lpath, dump_path);
4605 }
4588 4606
4589 /* Add to the path the lisp subdir of the installation 4607 /* Add site-lisp under the installation dir, if it exists. */
4590 dir, if it is accessible. Note: in out-of-tree builds, 4608 if (!no_site_lisp)
4591 this directory is empty save for Makefile. */ 4609 {
4592 tem = Fexpand_file_name (build_string ("lisp"), 4610 tem = Fexpand_file_name (build_string ("site-lisp"),
4593 Vinstallation_directory); 4611 Vinstallation_directory);
4594 tem1 = Ffile_accessible_directory_p (tem); 4612 tem1 = Ffile_accessible_directory_p (tem);
4595 if (!NILP (tem1)) 4613 if (!NILP (tem1))
4596 { 4614 {
4597 if (NILP (Fmember (tem, lpath))) 4615 if (NILP (Fmember (tem, lpath)))
4598 { 4616 lpath = Fcons (tem, lpath);
4599 /* We are running uninstalled. The default load-path
4600 points to the eventual installed lisp directories.
4601 We should not use those now, even if they exist,
4602 so start over from a clean slate. */
4603 lpath = list1 (tem);
4604 }
4605 }
4606 else
4607 /* That dir doesn't exist, so add the build-time
4608 Lisp dirs instead. */
4609 {
4610 Lisp_Object dump_path =
4611 decode_env_path (0, PATH_DUMPLOADSEARCH, 0);
4612 lpath = nconc2 (lpath, dump_path);
4613 } 4617 }
4618 }
4614 4619
4615 /* Add site-lisp under the installation dir, if it exists. */ 4620 /* If Emacs was not built in the source directory,
4616 if (!no_site_lisp) 4621 and it is run from where it was built, add to load-path
4617 { 4622 the lisp and site-lisp dirs under that directory. */
4618 tem = Fexpand_file_name (build_string ("site-lisp"),
4619 Vinstallation_directory);
4620 tem1 = Ffile_accessible_directory_p (tem);
4621 if (!NILP (tem1))
4622 {
4623 if (NILP (Fmember (tem, lpath)))
4624 lpath = Fcons (tem, lpath);
4625 }
4626 }
4627 4623
4628 /* If Emacs was not built in the source directory, 4624 if (NILP (Fequal (Vinstallation_directory, Vsource_directory)))
4629 and it is run from where it was built, add to load-path 4625 {
4630 the lisp and site-lisp dirs under that directory. */ 4626 Lisp_Object tem2;
4627
4628 tem = Fexpand_file_name (build_string ("src/Makefile"),
4629 Vinstallation_directory);
4630 tem1 = Ffile_exists_p (tem);
4631 4631
4632 if (NILP (Fequal (Vinstallation_directory, Vsource_directory))) 4632 /* Don't be fooled if they moved the entire source tree
4633 AFTER dumping Emacs. If the build directory is indeed
4634 different from the source dir, src/Makefile.in and
4635 src/Makefile will not be found together. */
4636 tem = Fexpand_file_name (build_string ("src/Makefile.in"),
4637 Vinstallation_directory);
4638 tem2 = Ffile_exists_p (tem);
4639 if (!NILP (tem1) && NILP (tem2))
4633 { 4640 {
4634 Lisp_Object tem2; 4641 tem = Fexpand_file_name (build_string ("lisp"),
4635 4642 Vsource_directory);
4636 tem = Fexpand_file_name (build_string ("src/Makefile"),
4637 Vinstallation_directory);
4638 tem1 = Ffile_exists_p (tem);
4639
4640 /* Don't be fooled if they moved the entire source tree
4641 AFTER dumping Emacs. If the build directory is indeed
4642 different from the source dir, src/Makefile.in and
4643 src/Makefile will not be found together. */
4644 tem = Fexpand_file_name (build_string ("src/Makefile.in"),
4645 Vinstallation_directory);
4646 tem2 = Ffile_exists_p (tem);
4647 if (!NILP (tem1) && NILP (tem2))
4648 {
4649 tem = Fexpand_file_name (build_string ("lisp"),
4650 Vsource_directory);
4651 4643
4652 if (NILP (Fmember (tem, lpath))) 4644 if (NILP (Fmember (tem, lpath)))
4653 lpath = Fcons (tem, lpath); 4645 lpath = Fcons (tem, lpath);
4654 4646
4655 if (!no_site_lisp) 4647 if (!no_site_lisp)
4648 {
4649 tem = Fexpand_file_name (build_string ("site-lisp"),
4650 Vsource_directory);
4651 tem1 = Ffile_accessible_directory_p (tem);
4652 if (!NILP (tem1))
4656 { 4653 {
4657 tem = Fexpand_file_name (build_string ("site-lisp"), 4654 if (NILP (Fmember (tem, lpath)))
4658 Vsource_directory); 4655 lpath = Fcons (tem, lpath);
4659 tem1 = Ffile_accessible_directory_p (tem);
4660 if (!NILP (tem1))
4661 {
4662 if (NILP (Fmember (tem, lpath)))
4663 lpath = Fcons (tem, lpath);
4664 }
4665 } 4656 }
4666 } 4657 }
4667 } /* Vinstallation_directory != Vsource_directory */ 4658 }
4659 } /* Vinstallation_directory != Vsource_directory */
4668 4660
4669 } /* if Vinstallation_directory */ 4661 } /* if Vinstallation_directory */
4670 }
4671 else /* !initialized */
4672 {
4673 /* NORMAL refers to PATH_DUMPLOADSEARCH, ie the lisp dir in the
4674 source directory. We used to add ../lisp (ie the lisp dir in
4675 the build directory) at the front here, but that should not
4676 be necessary, since in out of tree builds lisp/ is empty, save
4677 for Makefile. */
4678 lpath = decode_env_path (0, normal, 0);
4679 }
4680#endif /* !CANNOT_DUMP */
4681 4662
4682 return lpath; 4663 return lpath;
4683} 4664}
@@ -4691,11 +4672,7 @@ init_lread (void)
4691 /* First, set Vload_path. */ 4672 /* First, set Vload_path. */
4692 4673
4693 /* Ignore EMACSLOADPATH when dumping. */ 4674 /* Ignore EMACSLOADPATH when dumping. */
4694#ifdef CANNOT_DUMP 4675 bool use_loadpath = !will_dump_p ();
4695 bool use_loadpath = true;
4696#else
4697 bool use_loadpath = NILP (Vpurify_flag);
4698#endif
4699 4676
4700 if (use_loadpath && egetenv ("EMACSLOADPATH")) 4677 if (use_loadpath && egetenv ("EMACSLOADPATH"))
4701 { 4678 {
@@ -4746,7 +4723,7 @@ init_lread (void)
4746 load_path_check (Vload_path); 4723 load_path_check (Vload_path);
4747 4724
4748 /* Add the site-lisp directories at the front. */ 4725 /* Add the site-lisp directories at the front. */
4749 if (initialized && !no_site_lisp && PATH_SITELOADSEARCH[0] != '\0') 4726 if (!will_dump_p () && !no_site_lisp && PATH_SITELOADSEARCH[0] != '\0')
4750 { 4727 {
4751 Lisp_Object sitelisp; 4728 Lisp_Object sitelisp;
4752 sitelisp = decode_env_path (0, PATH_SITELOADSEARCH, 0); 4729 sitelisp = decode_env_path (0, PATH_SITELOADSEARCH, 0);
diff --git a/src/macfont.m b/src/macfont.m
index 09c4ff31c88..59627823fae 100644
--- a/src/macfont.m
+++ b/src/macfont.m
@@ -35,6 +35,7 @@ Original author: YAMAMOTO Mitsuharu
35#include "nsterm.h" 35#include "nsterm.h"
36#include "macfont.h" 36#include "macfont.h"
37#include "macuvs.h" 37#include "macuvs.h"
38#include "pdumper.h"
38 39
39#include <libkern/OSByteOrder.h> 40#include <libkern/OSByteOrder.h>
40 41
@@ -1029,12 +1030,12 @@ macfont_handle_font_change_notification (CFNotificationCenterRef center,
1029static void 1030static void
1030macfont_init_font_change_handler (void) 1031macfont_init_font_change_handler (void)
1031{ 1032{
1032 static bool initialized = false; 1033 static bool xinitialized = false;
1033 1034
1034 if (initialized) 1035 if (xinitialized)
1035 return; 1036 return;
1036 1037
1037 initialized = true; 1038 xinitialized = true;
1038 CFNotificationCenterAddObserver 1039 CFNotificationCenterAddObserver
1039 (CFNotificationCenterGetLocalCenter (), NULL, 1040 (CFNotificationCenterGetLocalCenter (), NULL,
1040 macfont_handle_font_change_notification, 1041 macfont_handle_font_change_notification,
@@ -1646,7 +1647,7 @@ static int macfont_variation_glyphs (struct font *, int c,
1646 unsigned variations[256]); 1647 unsigned variations[256]);
1647static void macfont_filter_properties (Lisp_Object, Lisp_Object); 1648static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1648 1649
1649static struct font_driver const macfont_driver = 1650static struct font_driver macfont_driver =
1650 { 1651 {
1651 .type = LISPSYM_INITIALLY (Qmac_ct), 1652 .type = LISPSYM_INITIALLY (Qmac_ct),
1652 .get_cache = macfont_get_cache, 1653 .get_cache = macfont_get_cache,
@@ -4028,12 +4029,14 @@ mac_register_font_driver (struct frame *f)
4028} 4029}
4029 4030
4030 4031
4032
4033static void syms_of_macfont_for_pdumper (void);
4034
4031void 4035void
4032syms_of_macfont (void) 4036syms_of_macfont (void)
4033{ 4037{
4034 /* Core Text, for macOS. */ 4038 /* Core Text, for macOS. */
4035 DEFSYM (Qmac_ct, "mac-ct"); 4039 DEFSYM (Qmac_ct, "mac-ct");
4036 register_font_driver (&macfont_driver, NULL);
4037 4040
4038 /* The font property key specifying the font design destination. The 4041 /* The font property key specifying the font design destination. The
4039 value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video 4042 value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
@@ -4048,4 +4051,18 @@ syms_of_macfont (void)
4048 4051
4049 macfont_family_cache = Qnil; 4052 macfont_family_cache = Qnil;
4050 staticpro (&macfont_family_cache); 4053 staticpro (&macfont_family_cache);
4054
4055 pdumper_do_now_and_after_load (syms_of_macfont_for_pdumper);
4056}
4057
4058static void
4059syms_of_macfont_for_pdumper (void)
4060{
4061 if (dumped_with_pdumper_p ())
4062 macfont_family_cache = Qnil;
4063 else
4064 eassert (NILP (macfont_family_cache));
4065
4066 macfont_driver.type = Qmac_ct;
4067 register_font_driver (&macfont_driver, NULL);
4051} 4068}
diff --git a/src/menu.c b/src/menu.c
index c0e5bd9caf6..ea387dacbda 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -1576,9 +1576,10 @@ for instance using the window manager, then this produces a quit and
1576void 1576void
1577syms_of_menu (void) 1577syms_of_menu (void)
1578{ 1578{
1579 staticpro (&menu_items);
1580 menu_items = Qnil; 1579 menu_items = Qnil;
1580 staticpro (&menu_items);
1581 menu_items_inuse = Qnil; 1581 menu_items_inuse = Qnil;
1582 staticpro (&menu_items_inuse);
1582 1583
1583 defsubr (&Sx_popup_menu); 1584 defsubr (&Sx_popup_menu);
1584 defsubr (&Sx_popup_dialog); 1585 defsubr (&Sx_popup_dialog);
diff --git a/src/minibuf.c b/src/minibuf.c
index c1fbfb40857..321fda1ba88 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -32,6 +32,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
32#include "keymap.h" 32#include "keymap.h"
33#include "sysstdio.h" 33#include "sysstdio.h"
34#include "systty.h" 34#include "systty.h"
35#include "pdumper.h"
35 36
36/* List of buffers for use as minibuffers. 37/* List of buffers for use as minibuffers.
37 The first element of the list is used for the outermost minibuffer 38 The first element of the list is used for the outermost minibuffer
@@ -1198,6 +1199,9 @@ is used to further constrain the set of candidates. */)
1198 bucket = AREF (collection, idx); 1199 bucket = AREF (collection, idx);
1199 } 1200 }
1200 1201
1202 if (HASH_TABLE_P (collection))
1203 hash_rehash_if_needed (XHASH_TABLE (collection));
1204
1201 while (1) 1205 while (1)
1202 { 1206 {
1203 /* Get the next element of the alist, obarray, or hash-table. */ 1207 /* Get the next element of the alist, obarray, or hash-table. */
@@ -1858,21 +1862,36 @@ If no minibuffer is active, return nil. */)
1858} 1862}
1859 1863
1860 1864
1865
1866static void init_minibuf_once_for_pdumper (void);
1867
1861void 1868void
1862init_minibuf_once (void) 1869init_minibuf_once (void)
1863{ 1870{
1864 Vminibuffer_list = Qnil;
1865 staticpro (&Vminibuffer_list); 1871 staticpro (&Vminibuffer_list);
1872 pdumper_do_now_and_after_load (init_minibuf_once_for_pdumper);
1866} 1873}
1867 1874
1868void 1875static void
1869syms_of_minibuf (void) 1876init_minibuf_once_for_pdumper (void)
1870{ 1877{
1878 PDUMPER_IGNORE (minibuf_level);
1879 PDUMPER_IGNORE (minibuf_prompt_width);
1880
1881 /* We run this function on first initialization and whenever we
1882 restore from a pdumper image. pdumper doesn't try to preserve
1883 frames, windows, and so on, so reset everything related here. */
1884 Vminibuffer_list = Qnil;
1871 minibuf_level = 0; 1885 minibuf_level = 0;
1872 minibuf_prompt = Qnil; 1886 minibuf_prompt = Qnil;
1873 staticpro (&minibuf_prompt);
1874
1875 minibuf_save_list = Qnil; 1887 minibuf_save_list = Qnil;
1888 last_minibuf_string = Qnil;
1889}
1890
1891void
1892syms_of_minibuf (void)
1893{
1894 staticpro (&minibuf_prompt);
1876 staticpro (&minibuf_save_list); 1895 staticpro (&minibuf_save_list);
1877 1896
1878 DEFSYM (Qcompletion_ignore_case, "completion-ignore-case"); 1897 DEFSYM (Qcompletion_ignore_case, "completion-ignore-case");
@@ -1882,7 +1901,6 @@ syms_of_minibuf (void)
1882 DEFSYM (Qminibuffer_completion_table, "minibuffer-completion-table"); 1901 DEFSYM (Qminibuffer_completion_table, "minibuffer-completion-table");
1883 1902
1884 staticpro (&last_minibuf_string); 1903 staticpro (&last_minibuf_string);
1885 last_minibuf_string = Qnil;
1886 1904
1887 DEFSYM (Qcustom_variable_history, "custom-variable-history"); 1905 DEFSYM (Qcustom_variable_history, "custom-variable-history");
1888 Fset (Qcustom_variable_history, Qnil); 1906 Fset (Qcustom_variable_history, Qnil);
diff --git a/src/nsfns.m b/src/nsfns.m
index 887d6b10aa5..60d62310bb0 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -49,7 +49,6 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
49#include "macfont.h" 49#include "macfont.h"
50#endif 50#endif
51 51
52
53#ifdef HAVE_NS 52#ifdef HAVE_NS
54 53
55static EmacsTooltip *ns_tooltip = nil; 54static EmacsTooltip *ns_tooltip = nil;
@@ -3125,7 +3124,6 @@ handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent)
3125 3124
3126 ========================================================================== */ 3125 ========================================================================== */
3127 3126
3128
3129void 3127void
3130syms_of_nsfns (void) 3128syms_of_nsfns (void)
3131{ 3129{
@@ -3215,5 +3213,6 @@ Default is t. */);
3215 3213
3216 as_status = 0; 3214 as_status = 0;
3217 as_script = Qnil; 3215 as_script = Qnil;
3216 staticpro (&as_script);
3218 as_result = 0; 3217 as_result = 0;
3219} 3218}
diff --git a/src/nsfont.m b/src/nsfont.m
index b59f87f4682..9721e489357 100644
--- a/src/nsfont.m
+++ b/src/nsfont.m
@@ -36,6 +36,7 @@ Author: Adrian Robert (arobert@cogsci.ucsd.edu)
36#include "character.h" 36#include "character.h"
37#include "font.h" 37#include "font.h"
38#include "termchar.h" 38#include "termchar.h"
39#include "pdumper.h"
39 40
40/* TODO: Drop once we can assume gnustep-gui 0.17.1. */ 41/* TODO: Drop once we can assume gnustep-gui 0.17.1. */
41#ifdef NS_IMPL_GNUSTEP 42#ifdef NS_IMPL_GNUSTEP
@@ -1483,6 +1484,8 @@ ns_dump_glyphstring (struct glyph_string *s)
1483 fprintf (stderr, "\n"); 1484 fprintf (stderr, "\n");
1484} 1485}
1485 1486
1487static void syms_of_nsfont_for_pdumper (void);
1488
1486struct font_driver const nsfont_driver = 1489struct font_driver const nsfont_driver =
1487 { 1490 {
1488 .type = LISPSYM_INITIALLY (Qns), 1491 .type = LISPSYM_INITIALLY (Qns),
@@ -1502,13 +1505,17 @@ struct font_driver const nsfont_driver =
1502void 1505void
1503syms_of_nsfont (void) 1506syms_of_nsfont (void)
1504{ 1507{
1505 register_font_driver (&nsfont_driver, NULL);
1506 DEFSYM (Qcondensed, "condensed"); 1508 DEFSYM (Qcondensed, "condensed");
1507 DEFSYM (Qexpanded, "expanded"); 1509 DEFSYM (Qexpanded, "expanded");
1508 DEFSYM (Qapple, "apple"); 1510 DEFSYM (Qapple, "apple");
1509 DEFSYM (Qmedium, "medium"); 1511 DEFSYM (Qmedium, "medium");
1510 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script, 1512 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1511 doc: /* Internal use: maps font registry to Unicode script. */); 1513 doc: /* Internal use: maps font registry to Unicode script. */);
1514 pdumper_do_now_and_after_load (syms_of_nsfont_for_pdumper);
1515}
1512 1516
1513 ascii_printable = NULL; 1517static void
1518syms_of_nsfont_for_pdumper (void)
1519{
1520 register_font_driver (&nsfont_driver, NULL);
1514} 1521}
diff --git a/src/nsmenu.m b/src/nsmenu.m
index de5db868223..34ec980856a 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -37,6 +37,7 @@ Carbon version by Yamamoto Mitsuharu. */
37#include "termhooks.h" 37#include "termhooks.h"
38#include "keyboard.h" 38#include "keyboard.h"
39#include "menu.h" 39#include "menu.h"
40#include "pdumper.h"
40 41
41#define NSMENUPROFILE 0 42#define NSMENUPROFILE 0
42 43
@@ -1893,6 +1894,7 @@ syms_of_nsmenu (void)
1893 /* Don't know how to keep track of this in Next/Open/GNUstep. Always 1894 /* Don't know how to keep track of this in Next/Open/GNUstep. Always
1894 update menus there. */ 1895 update menus there. */
1895 trackingMenu = 1; 1896 trackingMenu = 1;
1897 PDUMPER_REMEMBER_SCALAR (trackingMenu);
1896#endif 1898#endif
1897 defsubr (&Sns_reset_menu); 1899 defsubr (&Sns_reset_menu);
1898 defsubr (&Smenu_or_popup_active_p); 1900 defsubr (&Smenu_or_popup_active_p);
diff --git a/src/nsterm.m b/src/nsterm.m
index 6383e4b7ab5..29aa6214527 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -60,6 +60,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
60#include "keyboard.h" 60#include "keyboard.h"
61#include "buffer.h" 61#include "buffer.h"
62#include "font.h" 62#include "font.h"
63#include "pdumper.h"
63 64
64#ifdef NS_IMPL_GNUSTEP 65#ifdef NS_IMPL_GNUSTEP
65#include "process.h" 66#include "process.h"
@@ -9326,6 +9327,7 @@ syms_of_nsterm (void)
9326 NSTRACE ("syms_of_nsterm"); 9327 NSTRACE ("syms_of_nsterm");
9327 9328
9328 ns_antialias_threshold = 10.0; 9329 ns_antialias_threshold = 10.0;
9330 PDUMPER_REMEMBER_SCALAR (ns_antialias_threshold);
9329 9331
9330 /* From 23+ we need to tell emacs what modifiers there are. */ 9332 /* From 23+ we need to tell emacs what modifiers there are. */
9331 DEFSYM (Qmodifier_value, "modifier-value"); 9333 DEFSYM (Qmodifier_value, "modifier-value");
diff --git a/src/pdumper.c b/src/pdumper.c
new file mode 100644
index 00000000000..cf2aaf474bb
--- /dev/null
+++ b/src/pdumper.c
@@ -0,0 +1,5593 @@
1#include <config.h>
2
3#include <errno.h>
4#include <fcntl.h>
5#include <limits.h>
6#include <math.h>
7#include <stdarg.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <sys/mman.h>
12#include <sys/param.h>
13#include <sys/stat.h>
14#include <sys/types.h>
15#include <unistd.h>
16
17#include "blockinput.h"
18#include "buffer.h"
19#include "charset.h"
20#include "coding.h"
21#include "fingerprint.h"
22#include "frame.h"
23#include "getpagesize.h"
24#include "intervals.h"
25#include "lisp.h"
26#include "pdumper.h"
27#include "window.h"
28#include "systime.h"
29#include "thread.h"
30#include "bignum.h"
31
32#include "dmpstruct.h"
33
34/*
35 TODO:
36
37 - Two-pass dumping: first assemble object list, then write all.
38 This way, we can perform arbitrary reordering or maybe use fancy
39 graph algorithms to get better locality.
40
41 - Don't emit relocations that happen to set Emacs memory locations
42 to values they will already have.
43
44 - Nullify frame_and_buffer_state.
45
46 - Preferred base address for relocation-free non-PIC startup.
47
48 - Compressed dump support.
49
50*/
51
52#ifdef HAVE_PDUMPER
53
54/* CHECK_STRUCTS being true makes the build break if we notice
55 changes to the source defining certain Lisp structures we dump. If
56 you change one of these structures, check that the pdumper code is
57 still valid and update the hash from the dmpstruct.h generated by
58 your new code. */
59#ifndef CHECK_STRUCTS
60# define CHECK_STRUCTS 1
61#endif
62
63#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
64# pragma GCC diagnostic error "-Wconversion"
65# pragma GCC diagnostic error "-Wshadow"
66# define ALLOW_IMPLICIT_CONVERSION \
67 _Pragma ("GCC diagnostic push") \
68 _Pragma ("GCC diagnostic ignored \"-Wconversion\"")
69 _Pragma ("GCC diagnostic ignored \"-Wsign-conversion\"")
70# define DISALLOW_IMPLICIT_CONVERSION \
71 _Pragma ("GCC diagnostic pop")
72#else
73# define ALLOW_IMPLICIT_CONVERSION ((void)0)
74# define DISALLOW_IMPLICIT_CONVERSION ((void)0)
75#endif
76
77#define VM_POSIX 1
78#define VM_MS_WINDOWS 2
79
80#if defined (HAVE_MMAP) && defined (MAP_FIXED)
81# define VM_SUPPORTED VM_POSIX
82# if !defined (MAP_POPULATE) && defined (MAP_PREFAULT_READ)
83# define MAP_POPULATE MAP_PREFAULT_READ
84# elif !defined (MAP_POPULATE)
85# define MAP_POPULATE 0
86# endif
87#elif defined (WINDOWSNT)
88 /* Use a float infinity, to avoid compiler warnings in comparing vs
89 candidates' score. */
90# undef INFINITY
91# define INFINITY __builtin_inff ()
92# include <windows.h>
93# define VM_SUPPORTED VM_MS_WINDOWS
94#else
95# define VM_SUPPORTED 0
96#endif
97
98#define DANGEROUS 0
99
100/* PDUMPER_CHECK_REHASHING being true causes the portable dumper to
101 check, for each hash table it dumps, that the hash table means the
102 same thing after rehashing. */
103#ifndef PDUMPER_CHECK_REHASHING
104# if ENABLE_CHECKING
105# define PDUMPER_CHECK_REHASHING 1
106# else
107# define PDUMPER_CHECK_REHASHING 0
108# endif
109#endif
110
111/* We require an architecture in which all pointers are the same size
112 and have the same layout, where pointers are either 32 or 64 bits
113 long, and where bytes have eight bits --- that is, a
114 general-purpose computer made after 1990. */
115verify (sizeof (ptrdiff_t) == sizeof (void*));
116verify (sizeof (intptr_t) == sizeof (ptrdiff_t));
117verify (sizeof (void (*)(void)) == sizeof (void*));
118verify (sizeof (ptrdiff_t) <= sizeof (Lisp_Object));
119verify (sizeof (ptrdiff_t) <= sizeof (EMACS_INT));
120verify (sizeof (off_t) == sizeof (int32_t) ||
121 sizeof (off_t) == sizeof (int64_t));
122verify (CHAR_BIT == 8);
123
124#define DIVIDE_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
125
126static const char dump_magic[16] = {
127 'D', 'U', 'M', 'P', 'E', 'D',
128 'G', 'N', 'U',
129 'E', 'M', 'A', 'C', 'S'
130};
131
132static pdumper_hook dump_hooks[24];
133static int nr_dump_hooks = 0;
134
135static struct
136{
137 void *mem;
138 int sz;
139} remembered_data[32];
140static int nr_remembered_data = 0;
141
142typedef int32_t dump_off;
143#define DUMP_OFF_MIN INT32_MIN
144#define DUMP_OFF_MAX INT32_MAX
145
146__attribute__((format (printf,1,2)))
147static void
148dump_trace (const char *fmt, ...)
149{
150 if (0)
151 {
152 va_list args;
153 va_start (args, fmt);
154 vfprintf (stderr, fmt, args);
155 va_end (args);
156 }
157}
158
159static ssize_t dump_read_all (int fd, void *buf, size_t bytes_to_read);
160
161static dump_off
162ptrdiff_t_to_dump_off (ptrdiff_t value)
163{
164 eassert (DUMP_OFF_MIN <= value);
165 eassert (value <= DUMP_OFF_MAX);
166 return (dump_off) value;
167}
168
169/* Worst-case allocation granularity on any system that might load
170 this dump. */
171static int
172dump_get_page_size (void)
173{
174#if defined (WINDOWSNT) || defined (CYGWIN)
175 return 64 * 1024; /* Worst-case allocation granularity. */
176#else
177 return getpagesize ();
178#endif
179}
180
181#define dump_offsetof(type, member) \
182 (ptrdiff_t_to_dump_off (offsetof (type, member)))
183
184enum dump_reloc_type
185 {
186 /* dump_ptr = dump_ptr + emacs_basis() */
187 RELOC_DUMP_TO_EMACS_PTR_RAW,
188 /* dump_ptr = dump_ptr + dump_base */
189 RELOC_DUMP_TO_DUMP_PTR_RAW,
190 /* dump_mpz = [rebuild bignum] */
191 RELOC_BIGNUM,
192 /* dump_lv = make_lisp_ptr (
193 dump_lv + dump_base,
194 type - RELOC_DUMP_TO_DUMP_LV)
195 (Special case for symbols: make_lisp_symbol)
196 Must be second-last. */
197 RELOC_DUMP_TO_DUMP_LV,
198 /* dump_lv = make_lisp_ptr (
199 dump_lv + emacs_basis(),
200 type - RELOC_DUMP_TO_DUMP_LV)
201 (Special case for symbols: make_lisp_symbol.)
202 Must be last. */
203 RELOC_DUMP_TO_EMACS_LV = RELOC_DUMP_TO_DUMP_LV + 8,
204 };
205
206enum emacs_reloc_type
207 {
208 /* Copy raw bytes from the dump into Emacs. The length field in
209 the emacs_reloc is the number of bytes to copy. */
210 RELOC_EMACS_COPY_FROM_DUMP,
211 /* Set a piece of memory in Emacs to a value we store directly in
212 this relocation. The length field contains the number of bytes
213 we actually copy into Emacs. */
214 RELOC_EMACS_IMMEDIATE,
215 /* Set an aligned pointer-sized object in Emacs to a pointer into
216 the loaded dump at the given offset. The length field is
217 always the machine word size. */
218 RELOC_EMACS_DUMP_PTR_RAW,
219 /* Set an aligned pointer-sized object in Emacs to point to
220 something also in Emacs. The length field is always
221 the machine word size. */
222 RELOC_EMACS_EMACS_PTR_RAW,
223 /* Set an aligned Lisp_Object in Emacs to point to a value in the
224 dump. The length field is the _tag type_ of the Lisp_Object,
225 not a byte count! */
226 RELOC_EMACS_DUMP_LV,
227 /* Set an aligned Lisp_Object in Emacs to point to a value in the
228 Emacs image. The length field is the _tag type_ of the
229 Lisp_Object, not a byte count! */
230 RELOC_EMACS_EMACS_LV,
231 };
232
233#define EMACS_RELOC_TYPE_BITS 3
234#define EMACS_RELOC_LENGTH_BITS \
235 (sizeof (dump_off) * CHAR_BIT - EMACS_RELOC_TYPE_BITS)
236
237struct emacs_reloc
238{
239 ENUM_BF (emacs_reloc_type) type : EMACS_RELOC_TYPE_BITS;
240 dump_off length : EMACS_RELOC_LENGTH_BITS;
241 dump_off emacs_offset;
242 union
243 {
244 dump_off dump_offset;
245 dump_off emacs_offset2;
246 intmax_t immediate;
247 } u;
248};
249
250/* Set the type of an Emacs relocation.
251
252 Also make sure that the type fits in the bitfield. */
253static void
254emacs_reloc_set_type (struct emacs_reloc *reloc,
255 enum emacs_reloc_type type)
256{
257 reloc->type = type;
258 eassert (reloc->type == type);
259}
260
261struct dump_table_locator
262{
263 /* Offset in dump, in bytes, of the first entry in the dump
264 table. */
265 dump_off offset;
266 /* Number of entries in the dump table. We need an explicit end
267 indicator (as opposed to a special sentinel) so we can efficiently
268 binary search over the relocation entries. */
269 dump_off nr_entries;
270};
271
272#define DUMP_RELOC_TYPE_BITS 5
273verify (RELOC_DUMP_TO_EMACS_LV + 8 < (1 << DUMP_RELOC_TYPE_BITS));
274
275#define DUMP_RELOC_ALIGNMENT_BITS 2
276#define DUMP_RELOC_OFFSET_BITS \
277 (sizeof (dump_off) * CHAR_BIT - DUMP_RELOC_TYPE_BITS)
278
279/* Minimum alignment required by dump file format. */
280#define DUMP_RELOCATION_ALIGNMENT (1<<DUMP_RELOC_ALIGNMENT_BITS)
281
282/* The alignment granularity (in bytes) for objects we store in the
283 dump. Always suitable for heap objects; may be more aligned. */
284#define DUMP_ALIGNMENT (max (GCALIGNMENT, DUMP_RELOCATION_ALIGNMENT))
285verify (DUMP_ALIGNMENT >= GCALIGNMENT);
286
287struct dump_reloc
288{
289 uint32_t raw_offset : DUMP_RELOC_OFFSET_BITS;
290 ENUM_BF (dump_reloc_type) type : DUMP_RELOC_TYPE_BITS;
291};
292verify (sizeof (struct dump_reloc) == sizeof (int32_t));
293
294/* Set the type of a dump relocation.
295
296 Also assert that the type fits in the bitfield. */
297static void
298dump_reloc_set_type (struct dump_reloc *reloc, enum dump_reloc_type type)
299{
300 reloc->type = type;
301 eassert (reloc->type == type);
302}
303
304static dump_off
305dump_reloc_get_offset (struct dump_reloc reloc)
306{
307 return reloc.raw_offset << DUMP_RELOC_ALIGNMENT_BITS;
308}
309
310static void
311dump_reloc_set_offset (struct dump_reloc *reloc, dump_off offset)
312{
313 eassert (offset >= 0);
314 ALLOW_IMPLICIT_CONVERSION;
315 reloc->raw_offset = offset >> DUMP_RELOC_ALIGNMENT_BITS;
316 DISALLOW_IMPLICIT_CONVERSION;
317 if (dump_reloc_get_offset (*reloc) != offset)
318 error ("dump relocation out of range");
319}
320
321static void dump_fingerprint (const char* label, const uint8_t* xfingerprint) {
322 fprintf (stderr, "%s: ", label);
323 for (int i = 0; i <32; ++i) {
324 fprintf (stderr, "%02x", (unsigned) xfingerprint[i]);
325 }
326 fprintf (stderr, "\n");
327}
328
329/* Format of an Emacs portable dump file. All offsets are relative to
330 the beginning of the file. An Emacs portable dump file is coupled
331 to exactly the Emacs binary that produced it, so details of
332 alignment and endianness are unimportant.
333
334 An Emacs dump file contains the contents of the Lisp heap.
335 On startup, Emacs can start faster by mapping a dump file into
336 memory and using the objects contained inside it instead of
337 performing initialization from scratch.
338
339 The dump file can be loaded at arbitrary locations in memory, so it
340 includes a table of relocations that let Emacs adjust the pointers
341 embedded in the dump file to account for the location where it was
342 actually loaded.
343
344 Dump files can contain pointers to other objects in the dump file
345 or to parts of the Emacs binary. */
346struct dump_header
347{
348 /* File type magic. */
349 char magic[sizeof (dump_magic)];
350
351 /* Associated Emacs binary. */
352 uint8_t fingerprint[32];
353
354 /* Relocation table for the dump file; each entry is a
355 struct dump_reloc. */
356 struct dump_table_locator dump_relocs;
357
358 /* "Relocation" table we abuse to hold information about the
359 location and type of each lisp object in the dump. We need for
360 pdumper_object_type and ultimately for conservative GC
361 correctness. */
362 struct dump_table_locator object_starts;
363
364 /* Relocation table for Emacs; each entry is a struct
365 emacs_reloc. */
366 struct dump_table_locator emacs_relocs;
367
368 /* Start of sub-region of hot region that we can discard after load
369 completes. The discardable region ends at cold_start.
370
371 This region contains objects that we copy into the Emacs image at
372 dump-load time. */
373 dump_off discardable_start;
374
375 /* Start of the region that does not require relocations and that we
376 expect never to be modified. This region can be memory-mapped
377 directly from the backing dump file with the reasonable
378 expectation of taking few copy-on-write faults.
379
380 For correctness, however, this region must be modifible, since in
381 rare cases it is possible to see modifications to these bytes.
382 For example, this region contains string data, and it's
383 technically possible for someone to ASET a string character
384 (although nobody tends to do that).
385
386 The start of the cold region is always aligned on a page
387 boundary. */
388 dump_off cold_start;
389};
390
391/* Double-ended singly linked list. */
392struct dump_tailq
393{
394 Lisp_Object head;
395 Lisp_Object tail;
396 intptr_t length;
397};
398
399/* Queue of objects to dump. */
400struct dump_queue
401{
402 /* Objects with no link weights at all. Kept in dump order. */
403 struct dump_tailq zero_weight_objects;
404 /* Objects with simple link weight: just one entry of type
405 WEIGHT_NORMAL. Score in this special case is non-decreasing as
406 position increases, so we can avoid the need to rescan a big list
407 for each object by storing these objects in order. */
408 struct dump_tailq one_weight_normal_objects;
409 /* Likewise, for objects with one WEIGHT_STRONG weight. */
410 struct dump_tailq one_weight_strong_objects;
411 /* List of objects with complex link weights --- i.e., not one of
412 the above cases. Order is irrelevant, since we scan the whole
413 list every time. Relatively few objects end up here. */
414 struct dump_tailq fancy_weight_objects;
415 /* Hash table of link weights: maps an object to a list of zero or
416 more (BASIS . WEIGHT) pairs. As a special case, an object with
417 zero weight is marked by Qt in the hash table --- this way, we
418 can distinguish objects we've seen but that have no weight from
419 ones that we haven't seen at all. */
420 Lisp_Object link_weights;
421 /* Hash table mapping object to a sequence number --- used to
422 resolve ties. */
423 Lisp_Object sequence_numbers;
424 dump_off next_sequence_number;
425};
426
427enum cold_op
428 {
429 COLD_OP_OBJECT,
430 COLD_OP_STRING,
431 COLD_OP_CHARSET,
432 COLD_OP_BUFFER,
433 COLD_OP_BIGNUM,
434 };
435
436/* This structure controls what operations we perform inside
437 dump_object. */
438struct dump_flags
439{
440 /* Actually write object contents to the dump. Without this flag
441 set, we still scan objects and enqueue pointed-to objects; making
442 this flag false is useful when we want to process an object's
443 referents normally, but dump an object itself separately,
444 later. */
445 bool_bf dump_object_contents : 1;
446 /* Record object starts. We turn this flag off when writing to the
447 discardable section so that we don't trick conservative GC into
448 thinking we have objects there. Ignored (we never record object
449 starts) if dump_object_contents is false. */
450 bool_bf record_object_starts : 1;
451 /* Pack objects tighter than GC memory alignment would normally
452 require. Useful for objects copied into the Emacs image instead
453 of used directly from the loaded dump.
454 */
455 bool_bf pack_objects : 1;
456 /* Sometimes we dump objects that we've already scanned for outbound
457 references to other objects. These objects should not cause new
458 objects to enter the object dumping queue. This flag causes Emacs
459 to assert that no new objects are enqueued while dumping. */
460 bool_bf assert_already_seen : 1;
461 /* Punt on unstable hash tables: defer them to ctx->deferred_hash_tables. */
462 bool_bf defer_hash_tables : 1;
463 /* Punt on symbols: defer them to ctx->deferred_symbols. */
464 bool_bf defer_symbols : 1;
465 /* Punt on cold objects: defer them to ctx->cold_queue. */
466 bool_bf defer_cold_objects : 1;
467 /* Punt on copied objects: defer them to ctx->copied_queue. */
468 bool_bf defer_copied_objects : 1;
469};
470
471/* Information we use while we dump. Note that we're not the garbage
472 collector and can operate under looser constraints: specifically,
473 we allocate memory during the dumping process. */
474struct dump_context
475{
476 /* Header we'll write to the dump file when done. */
477 struct dump_header header;
478
479 Lisp_Object old_purify_flag;
480 Lisp_Object old_post_gc_hook;
481
482#ifdef REL_ALLOC
483 bool blocked_ralloc;
484#endif
485
486 /* File descriptor for dumpfile; < 0 if closed. */
487 int fd;
488 /* Name of dump file --- used for error reporting. */
489 Lisp_Object dump_filename;
490 /* Current offset in dump file. */
491 dump_off offset;
492
493 /* Starting offset of current object. */
494 dump_off obj_offset;
495
496 /* Flags currently in effect for dumping. */
497 struct dump_flags flags;
498
499 dump_off end_heap;
500
501 /* Hash mapping objects we've already dumped to their offsets. */
502 Lisp_Object objects_dumped;
503
504 /* Hash mapping objects to where we got them. Used for debugging. */
505 Lisp_Object referrers;
506 Lisp_Object current_referrer;
507 bool have_current_referrer;
508
509 /* Queue of objects to dump. */
510 struct dump_queue dump_queue;
511
512 /* Deferred object lists. */
513 Lisp_Object deferred_hash_tables;
514 Lisp_Object deferred_symbols;
515
516 /* Fixups in the dump file. */
517 Lisp_Object fixups;
518
519 /* Hash table of staticpro values: avoids double relocations. */
520 Lisp_Object staticpro_table;
521
522 /* Hash table mapping symbols to their pre-copy-queue fwd or blv
523 structures (which we dump immediately before the start of the
524 discardable section). */
525 Lisp_Object symbol_aux;
526 /* Queue of copied objects for special treatment. */
527 Lisp_Object copied_queue;
528 /* Queue of cold objects to dump. */
529 Lisp_Object cold_queue;
530
531 /* Relocations in the dump. */
532 Lisp_Object dump_relocs;
533
534 /* Object starts. */
535 Lisp_Object object_starts;
536
537 /* Relocations in Emacs. */
538 Lisp_Object emacs_relocs;
539
540 /* Hash table mapping bignums to their _data_ blobs, which we store
541 in the cold section. The actual Lisp_Bignum objects are normal
542 heap objects. */
543 Lisp_Object bignum_data;
544
545 unsigned number_hot_relocations;
546 unsigned number_discardable_relocations;
547};
548
549/* These special values for use as offsets in dump_remember_object and
550 dump_recall_object indicate that the corresponding object isn't in
551 the dump yet (and so it has no valid offset), but that it's on one
552 of our to-be-dumped-later object queues (or that we haven't seen it
553 at all). All values must be non-positive, since positive values
554 are physical dump offsets. */
555enum dump_object_special_offset
556 {
557 DUMP_OBJECT_IS_RUNTIME_MAGIC = -6,
558 DUMP_OBJECT_ON_COPIED_QUEUE = -5,
559 DUMP_OBJECT_ON_HASH_TABLE_QUEUE = -4,
560 DUMP_OBJECT_ON_SYMBOL_QUEUE = -3,
561 DUMP_OBJECT_ON_COLD_QUEUE = -2,
562 DUMP_OBJECT_ON_NORMAL_QUEUE = -1,
563 DUMP_OBJECT_NOT_SEEN = 0,
564 };
565
566/* Weights for score scores for object non-locality. */
567enum link_weight_enum
568 {
569 WEIGHT_NONE_VALUE = 0,
570 WEIGHT_NORMAL_VALUE = 1000,
571 WEIGHT_STRONG_VALUE = 1200,
572 };
573
574struct link_weight
575{
576 /* Wrapped in a struct to break unwanted implicit conversion. */
577 enum link_weight_enum value;
578};
579
580#define LINK_WEIGHT_LITERAL(x) ((struct link_weight){.value=(x)})
581#define WEIGHT_NONE LINK_WEIGHT_LITERAL (WEIGHT_NONE_VALUE)
582#define WEIGHT_NORMAL LINK_WEIGHT_LITERAL (WEIGHT_NORMAL_VALUE)
583#define WEIGHT_STRONG LINK_WEIGHT_LITERAL (WEIGHT_STRONG_VALUE)
584
585
586/* Dump file creation */
587
588static dump_off dump_object (struct dump_context *ctx, Lisp_Object object);
589static dump_off dump_object_for_offset (
590 struct dump_context *ctx, Lisp_Object object);
591
592/* Like the Lisp function `push'. Return NEWELT. */
593static Lisp_Object
594dump_push (Lisp_Object *where, Lisp_Object newelt)
595{
596 *where = Fcons (newelt, *where);
597 return newelt;
598}
599
600/* Like the Lisp function `pop'. */
601static Lisp_Object
602dump_pop (Lisp_Object *where)
603{
604 Lisp_Object ret = XCAR (*where);
605 *where = XCDR (*where);
606 return ret;
607}
608
609static bool
610dump_tracking_referrers_p (struct dump_context *ctx)
611{
612 return !NILP (ctx->referrers);
613}
614
615static void
616dump_set_have_current_referrer (struct dump_context *ctx, bool have)
617{
618#ifdef ENABLE_CHECKING
619 ctx->have_current_referrer = have;
620#endif
621}
622
623/* Remember the reason objects are enqueued.
624
625 Until DUMP_CLEAR_REFERRER is called, any objects enqueued are being
626 enqueued because OBJECT refers to them. It is not legal to enqueue
627 objects without a referer set. We check this constraint
628 at runtime.
629
630 It is illegal to call DUMP_SET_REFERRER twice without an
631 intervening call to DUMP_CLEAR_REFERRER.
632
633 Define as a macro so we can avoid evaluating OBJECT
634 if we dont want referrer tracking. */
635#define DUMP_SET_REFERRER(ctx, object) \
636 do \
637 { \
638 struct dump_context *_ctx = (ctx); \
639 eassert (!_ctx->have_current_referrer); \
640 dump_set_have_current_referrer (_ctx, true); \
641 if (dump_tracking_referrers_p (_ctx)) \
642 ctx->current_referrer = (object); \
643 } \
644 while (0)
645
646/* Unset the referer that DUMP_SET_REFERRER set.
647
648 Named with upper-case letters for symmetry with
649 DUMP_SET_REFERRER. */
650static void
651DUMP_CLEAR_REFERRER (struct dump_context *ctx)
652{
653 eassert (ctx->have_current_referrer);
654 dump_set_have_current_referrer (ctx, false);
655 if (dump_tracking_referrers_p (ctx))
656 ctx->current_referrer = Qnil;
657}
658
659static Lisp_Object
660dump_ptr_referrer (const char *label, void *address)
661{
662 char buf[128];
663 buf[0] = '\0';
664 sprintf (buf, "%s @ %p", label, address);
665 return build_string (buf);
666}
667
668static void
669print_paths_to_root (struct dump_context *ctx, Lisp_Object object);
670
671static void dump_remember_cold_op (struct dump_context *ctx,
672 enum cold_op op,
673 Lisp_Object arg);
674
675_Noreturn
676static void
677error_unsupported_dump_object (struct dump_context *ctx,
678 Lisp_Object object,
679 const char* msg)
680{
681 if (dump_tracking_referrers_p (ctx))
682 print_paths_to_root (ctx, object);
683 error ("unsupported object type in dump: %s", msg);
684}
685
686static uintptr_t
687emacs_basis (void)
688{
689 return (uintptr_t) &Vpurify_flag;
690}
691
692static void *
693emacs_ptr (const ptrdiff_t offset)
694{
695 /* TODO: assert somehow that the result is actually in the Emacs
696 image. */
697 return (void *) (emacs_basis () + offset);
698}
699
700static dump_off
701emacs_offset (const void *emacs_ptr)
702{
703 /* TODO: assert that EMACS_PTR is actually in the Emacs image. */
704 eassert (emacs_ptr != NULL);
705 intptr_t emacs_ptr_value = (intptr_t) emacs_ptr;
706 ptrdiff_t emacs_ptr_relative = emacs_ptr_value - (intptr_t) emacs_basis ();
707 return ptrdiff_t_to_dump_off (emacs_ptr_relative);
708}
709
710/* Return whether OBJECT is a symbol the storage of which is built
711 into Emacs (and so is invariant across ASLR). */
712static bool
713dump_builtin_symbol_p (Lisp_Object object)
714{
715 if (!SYMBOLP (object))
716 return false;
717 char* bp = (char*) lispsym;
718 struct Lisp_Symbol *s = XSYMBOL (object);
719 char* sp = (char*) s;
720 return bp <= sp && sp < bp + sizeof (lispsym);
721}
722
723/* Return whether OBJECT has the same bit pattern in all Emacs
724 invocations --- i.e., is invariant across a dump. Note that some
725 self-representing objects still need to be dumped!
726*/
727static bool
728dump_object_self_representing_p (Lisp_Object object)
729{
730 bool result;
731 ALLOW_IMPLICIT_CONVERSION;
732 result = FIXNUMP (object) || dump_builtin_symbol_p (object);
733 DISALLOW_IMPLICIT_CONVERSION;
734 return result;
735}
736
737#define DEFINE_FROMLISP_FUNC(fn, type) \
738 static type \
739 fn (Lisp_Object value) \
740 { \
741 ALLOW_IMPLICIT_CONVERSION; \
742 if (FIXNUMP (value)) \
743 return XFIXNUM (value); \
744 eassert (BIGNUMP (value)); \
745 return TYPE_SIGNED (type) \
746 ? bignum_to_intmax (value) \
747 : bignum_to_uintmax (value); \
748 DISALLOW_IMPLICIT_CONVERSION; \
749 }
750
751#define DEFINE_TOLISP_FUNC(fn, type) \
752 static Lisp_Object \
753 fn (type value) \
754 { \
755 return INT_TO_INTEGER (value); \
756 }
757
758DEFINE_FROMLISP_FUNC (intmax_t_from_lisp, intmax_t);
759DEFINE_TOLISP_FUNC (intmax_t_to_lisp, intmax_t);
760DEFINE_FROMLISP_FUNC (dump_off_from_lisp, dump_off);
761DEFINE_TOLISP_FUNC (dump_off_to_lisp, dump_off);
762
763static void
764dump_write (struct dump_context *ctx, const void *buf, dump_off nbyte)
765{
766 eassert (nbyte == 0 || buf != NULL);
767 eassert (ctx->obj_offset == 0);
768 eassert (ctx->flags.dump_object_contents);
769 if (emacs_write (ctx->fd, buf, nbyte) < nbyte)
770 report_file_error ("Could not write to dump file", ctx->dump_filename);
771 ctx->offset += nbyte;
772}
773
774static Lisp_Object
775make_eq_hash_table (void)
776{
777 return CALLN (Fmake_hash_table, QCtest, Qeq);
778}
779
780static void
781dump_tailq_init (struct dump_tailq *tailq)
782{
783 tailq->head = tailq->tail = Qnil;
784 tailq->length = 0;
785}
786
787static intptr_t
788dump_tailq_length (const struct dump_tailq *tailq)
789{
790 return tailq->length;
791}
792
793__attribute__((unused))
794static void
795dump_tailq_prepend (struct dump_tailq *tailq, Lisp_Object value)
796{
797 Lisp_Object link = Fcons (value, tailq->head);
798 tailq->head = link;
799 if (NILP (tailq->tail))
800 tailq->tail = link;
801 tailq->length += 1;
802}
803
804__attribute__((unused))
805static void
806dump_tailq_append (struct dump_tailq *tailq, Lisp_Object value)
807{
808 Lisp_Object link = Fcons (value, Qnil);
809 if (NILP (tailq->head))
810 {
811 eassert (NILP (tailq->tail));
812 tailq->head = tailq->tail = link;
813 }
814 else
815 {
816 eassert (!NILP (tailq->tail));
817 XSETCDR (tailq->tail, link);
818 tailq->tail = link;
819 }
820 tailq->length += 1;
821}
822
823static bool
824dump_tailq_empty_p (struct dump_tailq *tailq)
825{
826 return NILP (tailq->head);
827}
828
829static Lisp_Object
830dump_tailq_peek (struct dump_tailq *tailq)
831{
832 eassert (!dump_tailq_empty_p (tailq));
833 return XCAR (tailq->head);
834}
835
836static Lisp_Object
837dump_tailq_pop (struct dump_tailq *tailq)
838{
839 eassert (!dump_tailq_empty_p (tailq));
840 eassert (tailq->length > 0);
841 tailq->length -= 1;
842 Lisp_Object value = XCAR (tailq->head);
843 tailq->head = XCDR (tailq->head);
844 if (NILP (tailq->head))
845 tailq->tail = Qnil;
846 return value;
847}
848
849static void
850dump_seek (struct dump_context *ctx, dump_off offset)
851{
852 eassert (ctx->obj_offset == 0);
853 if (lseek (ctx->fd, offset, SEEK_SET) < 0)
854 report_file_error ("Setting file position",
855 ctx->dump_filename);
856 ctx->offset = offset;
857}
858
859static void
860dump_write_zero (struct dump_context *ctx, dump_off nbytes)
861{
862 while (nbytes > 0)
863 {
864 uintmax_t zero = 0;
865 dump_off to_write = sizeof (zero);
866 if (to_write > nbytes)
867 to_write = nbytes;
868 dump_write (ctx, &zero, to_write);
869 nbytes -= to_write;
870 }
871}
872
873static void
874dump_align_output (struct dump_context *ctx, int alignment)
875{
876 if (ctx->offset % alignment != 0)
877 dump_write_zero (ctx, alignment - (ctx->offset % alignment));
878}
879
880static dump_off
881dump_object_start (struct dump_context *ctx,
882 void *out,
883 dump_off outsz)
884{
885 /* We dump only one object at a time, so obj_offset should be
886 invalid on entry to this function. */
887 eassert (ctx->obj_offset == 0);
888 int alignment = ctx->flags.pack_objects ? 1 : DUMP_ALIGNMENT;
889 if (ctx->flags.dump_object_contents)
890 dump_align_output (ctx, alignment);
891 ctx->obj_offset = ctx->offset;
892 memset (out, 0, outsz);
893 return ctx->offset;
894}
895
896static dump_off
897dump_object_finish (struct dump_context *ctx,
898 const void *out,
899 dump_off sz)
900{
901 dump_off offset = ctx->obj_offset;
902 eassert (offset > 0);
903 eassert (offset == ctx->offset); /* No intervening writes. */
904 ctx->obj_offset = 0;
905 if (ctx->flags.dump_object_contents)
906 dump_write (ctx, out, sz);
907 return offset;
908}
909
910/* Return offset at which OBJECT has been dumped, or one of the dump_object_special_offset
911 negative values, or DUMP_OBJECT_NOT_SEEN. */
912static dump_off
913dump_recall_object (struct dump_context *ctx, Lisp_Object object)
914{
915 Lisp_Object dumped = ctx->objects_dumped;
916 return dump_off_from_lisp (Fgethash (object, dumped,
917 make_fixnum (DUMP_OBJECT_NOT_SEEN)));
918}
919
920static void
921dump_remember_object (struct dump_context *ctx,
922 Lisp_Object object,
923 dump_off offset)
924{
925 Fputhash (object,
926 dump_off_to_lisp (offset),
927 ctx->objects_dumped);
928}
929
930static void
931dump_note_reachable (struct dump_context *ctx, Lisp_Object object)
932{
933 eassert (ctx->have_current_referrer);
934 if (!dump_tracking_referrers_p (ctx))
935 return;
936 Lisp_Object referrer = ctx->current_referrer;
937 Lisp_Object obj_referrers = Fgethash (object, ctx->referrers, Qnil);
938 if (NILP (Fmemq (referrer, obj_referrers)))
939 Fputhash (object, Fcons (referrer, obj_referrers), ctx->referrers);
940}
941
942/* If this object lives in the Emacs image and not on the heap, return
943 a pointer to the object data. Otherwise, return NULL. */
944static void*
945dump_object_emacs_ptr (Lisp_Object lv)
946{
947 if (SUBRP (lv))
948 return XSUBR (lv);
949 if (dump_builtin_symbol_p (lv))
950 return XSYMBOL (lv);
951 if (XTYPE (lv) == Lisp_Vectorlike &&
952 PSEUDOVECTOR_TYPEP (&XVECTOR (lv)->header, PVEC_THREAD) &&
953 main_thread_p (XTHREAD (lv)))
954 return XTHREAD (lv);
955 return NULL;
956}
957
958static void
959dump_queue_init (struct dump_queue *dump_queue)
960{
961 dump_tailq_init (&dump_queue->zero_weight_objects);
962 dump_tailq_init (&dump_queue->one_weight_normal_objects);
963 dump_tailq_init (&dump_queue->one_weight_strong_objects);
964 dump_tailq_init (&dump_queue->fancy_weight_objects);
965 dump_queue->link_weights = make_eq_hash_table ();
966 dump_queue->sequence_numbers = make_eq_hash_table ();
967 dump_queue->next_sequence_number = 1;
968}
969
970static bool
971dump_queue_empty_p (struct dump_queue *dump_queue)
972{
973 bool is_empty =
974 EQ (Fhash_table_count (dump_queue->sequence_numbers),
975 make_fixnum (0));
976 eassert (EQ (Fhash_table_count (dump_queue->sequence_numbers),
977 Fhash_table_count (dump_queue->link_weights)));
978 if (!is_empty)
979 {
980 eassert (
981 !dump_tailq_empty_p (&dump_queue->zero_weight_objects) ||
982 !dump_tailq_empty_p (&dump_queue->one_weight_normal_objects) ||
983 !dump_tailq_empty_p (&dump_queue->one_weight_strong_objects) ||
984 !dump_tailq_empty_p (&dump_queue->fancy_weight_objects));
985 }
986 else
987 {
988 /* If we're empty, we can still have a few stragglers on one of
989 the above queues. */
990 }
991
992 return is_empty;
993}
994
995static void
996dump_queue_push_weight (Lisp_Object *weight_list,
997 dump_off basis,
998 struct link_weight weight)
999{
1000 if (EQ (*weight_list, Qt))
1001 *weight_list = Qnil;
1002 dump_push (weight_list, Fcons (dump_off_to_lisp (basis),
1003 dump_off_to_lisp (weight.value)));
1004}
1005
1006static void
1007dump_queue_enqueue (struct dump_queue *dump_queue,
1008 Lisp_Object object,
1009 dump_off basis,
1010 struct link_weight weight)
1011{
1012 Lisp_Object weights = Fgethash (object, dump_queue->link_weights, Qnil);
1013 Lisp_Object orig_weights = weights;
1014 /* N.B. want to find the last item of a given weight in each queue
1015 due to prepend use. */
1016 bool use_single_queues = true;
1017 if (NILP (weights))
1018 {
1019 /* Object is new. */
1020 dump_trace ("new object %016x weight=%u\n",
1021 (unsigned) XLI (object),
1022 (unsigned) weight.value);
1023
1024 if (weight.value == WEIGHT_NONE.value)
1025 {
1026 eassert (weight.value == 0);
1027 dump_tailq_prepend (&dump_queue->zero_weight_objects, object);
1028 weights = Qt;
1029 }
1030 else if (!use_single_queues)
1031 {
1032 dump_tailq_prepend (&dump_queue->fancy_weight_objects, object);
1033 dump_queue_push_weight (&weights, basis, weight);
1034 }
1035 else if (weight.value == WEIGHT_NORMAL.value)
1036 {
1037 dump_tailq_prepend (&dump_queue->one_weight_normal_objects, object);
1038 dump_queue_push_weight (&weights, basis, weight);
1039 }
1040 else if (weight.value == WEIGHT_STRONG.value)
1041 {
1042 dump_tailq_prepend (&dump_queue->one_weight_strong_objects, object);
1043 dump_queue_push_weight (&weights, basis, weight);
1044 }
1045 else
1046 {
1047 emacs_abort ();
1048 }
1049
1050 Fputhash (object,
1051 dump_off_to_lisp(dump_queue->next_sequence_number++),
1052 dump_queue->sequence_numbers);
1053 }
1054 else
1055 {
1056 /* Object was already on the queue. It's okay for an object to
1057 be on multiple queues so long as we maintain order
1058 invariants: attempting to dump an object multiple times is
1059 harmless, and most of the time, an object is only referenced
1060 once before being dumped, making this code path uncommon. */
1061 if (weight.value != WEIGHT_NONE.value)
1062 {
1063 if (EQ (weights, Qt))
1064 {
1065 /* Object previously had a zero weight. Once we
1066 incorporate the link weight attached to this call,
1067 the object will have a single weight. Put the object
1068 on the appropriate single-weight queue. */
1069 weights = Qnil;
1070 if (!use_single_queues)
1071 dump_tailq_prepend (&dump_queue->fancy_weight_objects, object);
1072 else if (weight.value == WEIGHT_NORMAL.value)
1073 dump_tailq_prepend (
1074 &dump_queue->one_weight_normal_objects, object);
1075 else if (weight.value == WEIGHT_STRONG.value)
1076 dump_tailq_prepend (
1077 &dump_queue->one_weight_strong_objects, object);
1078 else
1079 emacs_abort ();
1080 }
1081 else if (use_single_queues && NILP (XCDR (weights)))
1082 dump_tailq_prepend (&dump_queue->fancy_weight_objects, object);
1083 dump_queue_push_weight (&weights, basis, weight);
1084 }
1085 }
1086
1087 if (!EQ (weights, orig_weights))
1088 Fputhash (object, weights, dump_queue->link_weights);
1089}
1090
1091static float
1092dump_calc_link_score (dump_off basis,
1093 dump_off link_basis,
1094 dump_off link_weight)
1095{
1096 float distance = (float)(basis - link_basis);
1097 eassert (distance >= 0);
1098 float link_score = powf (distance, -0.2f);
1099 return powf (link_score, (float) link_weight / 1000.0f);
1100}
1101
1102/* Compute the score score for a queued object.
1103
1104 OBJECT is the object to query, which must currently be queued for
1105 dumping. BASIS is the offset at which we would be
1106 dumping the object; score is computed relative to BASIS and the
1107 various BASIS values supplied to dump_add_link_weight --- the
1108 further an object is from its referrers, the greater the
1109 score. */
1110static float
1111dump_queue_compute_score (struct dump_queue *dump_queue,
1112 Lisp_Object object,
1113 dump_off basis)
1114{
1115 float score = 0;
1116 Lisp_Object object_link_weights =
1117 Fgethash (object, dump_queue->link_weights, Qnil);
1118 if (EQ (object_link_weights, Qt))
1119 object_link_weights = Qnil;
1120 while (!NILP (object_link_weights))
1121 {
1122 Lisp_Object basis_weight_pair = dump_pop (&object_link_weights);
1123 dump_off link_basis = dump_off_from_lisp (XCAR (basis_weight_pair));
1124 dump_off link_weight = dump_off_from_lisp (XCDR (basis_weight_pair));
1125 score += dump_calc_link_score (basis, link_basis, link_weight);
1126 }
1127 return score;
1128}
1129
1130/* Scan the fancy part of the dump queue.
1131
1132 BASIS is the position at which to evaluate the score function,
1133 usually ctx->offset.
1134
1135 If we have at least one entry in the queue, return the pointer (in
1136 the singly-linked list) to the cons containing the object via
1137 *OUT_HIGHEST_SCORE_CONS_PTR and return its score.
1138
1139 If the queue is empty, set *OUT_HIGHEST_SCORE_CONS_PTR to NULL
1140 and return negative infinity. */
1141static float
1142dump_queue_scan_fancy (struct dump_queue *dump_queue,
1143 dump_off basis,
1144 Lisp_Object **out_highest_score_cons_ptr)
1145{
1146 Lisp_Object *cons_ptr = &dump_queue->fancy_weight_objects.head;
1147 Lisp_Object *highest_score_cons_ptr = NULL;
1148 float highest_score = -INFINITY;
1149 bool first = true;
1150
1151 while (!NILP (*cons_ptr))
1152 {
1153 Lisp_Object queued_object = XCAR (*cons_ptr);
1154 float score = dump_queue_compute_score (
1155 dump_queue, queued_object, basis);
1156 if (first || score >= highest_score)
1157 {
1158 highest_score_cons_ptr = cons_ptr;
1159 highest_score = score;
1160 if (first)
1161 first = false;
1162 }
1163 cons_ptr = &XCONS (*cons_ptr)->u.s.u.cdr;
1164 }
1165
1166 *out_highest_score_cons_ptr = highest_score_cons_ptr;
1167 return highest_score;
1168}
1169
1170/* Return the sequence number of OBJECT.
1171
1172 Return -1 if object doesn't have a sequence number. This situation
1173 can occur when we've double-queued an object. If this happens, we
1174 discard the errant object and try again. */
1175static dump_off
1176dump_queue_sequence (struct dump_queue *dump_queue,
1177 Lisp_Object object)
1178{
1179 Lisp_Object n = Fgethash (object, dump_queue->sequence_numbers, Qnil);
1180 return NILP (n) ? -1 : dump_off_from_lisp (n);
1181}
1182
1183/* Find score and sequence at head of a one-weight object queue.
1184
1185 Transparently discard stale objects from head of queue. BASIS
1186 is the baseness for score computation.
1187
1188 We organize these queues so that score is strictly decreasing, so
1189 examining the head is sufficient. */
1190static void
1191dump_queue_find_score_of_one_weight_queue (
1192 struct dump_queue *dump_queue,
1193 dump_off basis,
1194 struct dump_tailq *one_weight_queue,
1195 float *out_score,
1196 int *out_sequence)
1197{
1198 /* Transparently discard stale objects from the head of this queue. */
1199 do
1200 {
1201 if (dump_tailq_empty_p (one_weight_queue))
1202 {
1203 *out_score = -INFINITY;
1204 *out_sequence = 0;
1205 }
1206 else
1207 {
1208 Lisp_Object head = dump_tailq_peek (one_weight_queue);
1209 *out_sequence = dump_queue_sequence (dump_queue, head);
1210 if (*out_sequence < 0)
1211 dump_tailq_pop (one_weight_queue);
1212 else
1213 *out_score =
1214 dump_queue_compute_score (dump_queue, head, basis);
1215 }
1216 }
1217 while (*out_sequence < 0);
1218}
1219
1220/* Pop the next object to dump from the dump queue.
1221
1222 BASIS is the dump offset at which to evaluate score.
1223
1224 The object returned is the queued object with the greatest score;
1225 by side effect, the object is removed from the dump queue.
1226 The dump queue must not be empty. */
1227static Lisp_Object
1228dump_queue_dequeue (struct dump_queue *dump_queue, dump_off basis)
1229{
1230 eassert (EQ (Fhash_table_count (dump_queue->sequence_numbers),
1231 Fhash_table_count (dump_queue->link_weights)));
1232
1233 eassert (
1234 XFIXNUM (Fhash_table_count (dump_queue->sequence_numbers))
1235 <= (dump_tailq_length (&dump_queue->fancy_weight_objects) +
1236 dump_tailq_length (&dump_queue->zero_weight_objects) +
1237 dump_tailq_length (&dump_queue->one_weight_normal_objects) +
1238 dump_tailq_length (&dump_queue->one_weight_strong_objects)));
1239
1240 bool dump_object_counts = true;
1241 if (dump_object_counts)
1242 dump_trace (
1243 "dump_queue_dequeue basis=%d fancy=%u zero=%u "
1244 "normal=%u strong=%u hash=%u\n",
1245 basis,
1246 (unsigned) dump_tailq_length (&dump_queue->fancy_weight_objects),
1247 (unsigned) dump_tailq_length (&dump_queue->zero_weight_objects),
1248 (unsigned) dump_tailq_length (&dump_queue->one_weight_normal_objects),
1249 (unsigned) dump_tailq_length (&dump_queue->one_weight_strong_objects),
1250 (unsigned) XFIXNUM (Fhash_table_count (dump_queue->link_weights)));
1251
1252 static const int nr_candidates = 3;
1253 struct candidate {
1254 float score;
1255 dump_off sequence;
1256 } candidates[nr_candidates];
1257
1258 Lisp_Object *fancy_cons = NULL;
1259 candidates[0].sequence = 0;
1260 do
1261 {
1262 if (candidates[0].sequence < 0)
1263 *fancy_cons = XCDR (*fancy_cons); /* Discard stale object. */
1264 candidates[0].score = dump_queue_scan_fancy (
1265 dump_queue,
1266 basis,
1267 &fancy_cons);
1268 candidates[0].sequence =
1269 candidates[0].score > -INFINITY
1270 ? dump_queue_sequence (dump_queue, XCAR (*fancy_cons))
1271 : 0;
1272 }
1273 while (candidates[0].sequence < 0);
1274
1275 dump_queue_find_score_of_one_weight_queue (
1276 dump_queue,
1277 basis,
1278 &dump_queue->one_weight_normal_objects,
1279 &candidates[1].score,
1280 &candidates[1].sequence);
1281
1282 dump_queue_find_score_of_one_weight_queue (
1283 dump_queue,
1284 basis,
1285 &dump_queue->one_weight_strong_objects,
1286 &candidates[2].score,
1287 &candidates[2].sequence);
1288
1289 int best = -1;
1290 for (int i = 0; i < nr_candidates; ++i)
1291 {
1292 eassert (candidates[i].sequence >= 0);
1293 if (candidates[i].score > -INFINITY &&
1294 (best < 0 ||
1295 candidates[i].score > candidates[best].score ||
1296 (candidates[i].score == candidates[best].score
1297 && candidates[i].sequence < candidates[best].sequence)))
1298 best = i;
1299 }
1300
1301 Lisp_Object result;
1302 const char *src;
1303 if (best < 0)
1304 {
1305 src = "zero";
1306 result = dump_tailq_pop (&dump_queue->zero_weight_objects);
1307 }
1308 else if (best == 0)
1309 {
1310 src = "fancy";
1311 result = dump_tailq_pop (&dump_queue->fancy_weight_objects);
1312 }
1313 else if (best == 1)
1314 {
1315 src = "normal";
1316 result = dump_tailq_pop (&dump_queue->one_weight_normal_objects);
1317 }
1318 else if (best == 2)
1319 {
1320 src = "strong";
1321 result = dump_tailq_pop (&dump_queue->one_weight_strong_objects);
1322 }
1323 else
1324 emacs_abort ();
1325
1326 dump_trace (" result score=%f src=%s object=%016x\n",
1327 best < 0 ? -1.0 : (double) candidates[best].score,
1328 src,
1329 (unsigned) XLI (result));
1330
1331 {
1332 Lisp_Object weights = Fgethash (result, dump_queue->link_weights, Qnil);
1333 while (!NILP (weights) && CONSP (weights))
1334 {
1335 Lisp_Object basis_weight_pair = dump_pop (&weights);
1336 dump_off link_basis =
1337 dump_off_from_lisp (XCAR (basis_weight_pair));
1338 dump_off link_weight =
1339 dump_off_from_lisp (XCDR (basis_weight_pair));
1340 dump_trace (
1341 " link_basis=%d distance=%d weight=%d contrib=%f\n",
1342 link_basis,
1343 basis - link_basis,
1344 link_weight,
1345 (double) dump_calc_link_score (
1346 basis, link_basis, link_weight));
1347 }
1348 }
1349
1350 Fremhash (result, dump_queue->link_weights);
1351 Fremhash (result, dump_queue->sequence_numbers);
1352 return result;
1353}
1354
1355/* Return whether we need to write OBJECT to the dump file. */
1356static bool
1357dump_object_needs_dumping_p (Lisp_Object object)
1358{
1359 /* Some objects, like symbols, are self-representing because they
1360 have invariant bit patterns, but sometimes these objects have
1361 associated data too, and these data-carrying objects need to be
1362 included in the dump despite all references to them being
1363 bitwise-invariant. */
1364 return !dump_object_self_representing_p (object) ||
1365 dump_object_emacs_ptr (object);
1366}
1367
1368static void
1369dump_enqueue_object (struct dump_context *ctx,
1370 Lisp_Object object,
1371 struct link_weight weight)
1372{
1373 if (dump_object_needs_dumping_p (object))
1374 {
1375 dump_off state = dump_recall_object (ctx, object);
1376 bool already_dumped_object = state > DUMP_OBJECT_NOT_SEEN;
1377 if (ctx->flags.assert_already_seen)
1378 eassert (already_dumped_object);
1379 if (!already_dumped_object)
1380 {
1381 if (state == DUMP_OBJECT_NOT_SEEN)
1382 {
1383 state = DUMP_OBJECT_ON_NORMAL_QUEUE;
1384 dump_remember_object (ctx, object, state);
1385 }
1386 /* Note that we call dump_queue_enqueue even if the object
1387 is already on the normal queue: multiple enqueue calls
1388 can increase the object's weight. */
1389 if (state == DUMP_OBJECT_ON_NORMAL_QUEUE)
1390 dump_queue_enqueue (&ctx->dump_queue,
1391 object,
1392 ctx->offset,
1393 weight);
1394 }
1395 }
1396 /* Always remember the path to this object. */
1397 dump_note_reachable (ctx, object);
1398}
1399
1400static void
1401print_paths_to_root_1 (struct dump_context *ctx,
1402 Lisp_Object object,
1403 int level)
1404{
1405 Lisp_Object referrers = Fgethash (object, ctx->referrers, Qnil);
1406 while (!NILP (referrers))
1407 {
1408 Lisp_Object referrer = XCAR (referrers);
1409 referrers = XCDR (referrers);
1410 Lisp_Object repr = Fprin1_to_string (referrer, Qnil);
1411 for (int i = 0; i < level; ++i)
1412 fputc (' ', stderr);
1413 fprintf (stderr, "%s\n", SDATA (repr));
1414 print_paths_to_root_1 (ctx, referrer, level + 1);
1415 }
1416}
1417
1418static void
1419print_paths_to_root (struct dump_context *ctx, Lisp_Object object)
1420{
1421 print_paths_to_root_1 (ctx, object, 0);
1422}
1423
1424static void
1425dump_remember_cold_op (struct dump_context *ctx,
1426 enum cold_op op,
1427 Lisp_Object arg)
1428{
1429 if (ctx->flags.dump_object_contents)
1430 dump_push (&ctx->cold_queue, Fcons (make_fixnum (op), arg));
1431}
1432
1433/* Add a dump relocation that points into Emacs.
1434
1435 Add a relocation that updates the pointer stored at DUMP_OFFSET to
1436 point into the Emacs binary upon dump load. The pointer-sized
1437 value at DUMP_OFFSET in the dump file should contain a number
1438 relative to emacs_basis(). */
1439static void
1440dump_reloc_dump_to_emacs_ptr_raw (struct dump_context *ctx,
1441 dump_off dump_offset)
1442{
1443 if (ctx->flags.dump_object_contents)
1444 dump_push (&ctx->dump_relocs,
1445 list2 (make_fixnum (RELOC_DUMP_TO_EMACS_PTR_RAW),
1446 dump_off_to_lisp (dump_offset)));
1447}
1448
1449/* Add a dump relocation that points a Lisp_Object back at the dump.
1450
1451 Add a relocation that updates the Lisp_Object at DUMP_OFFSET in the
1452 dump to point to another object in the dump. The Lisp_Object-sized
1453 value at DUMP_OFFSET in the dump file should contain the offset of
1454 the target object relative to the start of the dump. */
1455static void
1456dump_reloc_dump_to_dump_lv (struct dump_context *ctx,
1457 dump_off dump_offset,
1458 enum Lisp_Type type)
1459{
1460 if (!ctx->flags.dump_object_contents)
1461 return;
1462
1463 int reloc_type;
1464 switch (type)
1465 {
1466 case Lisp_Symbol:
1467 case Lisp_String:
1468 case Lisp_Vectorlike:
1469 case Lisp_Cons:
1470 case Lisp_Float:
1471 reloc_type = RELOC_DUMP_TO_DUMP_LV + type;
1472 break;
1473 default:
1474 emacs_abort ();
1475 }
1476
1477 dump_push (&ctx->dump_relocs,
1478 list2 (make_fixnum (reloc_type),
1479 dump_off_to_lisp (dump_offset)));
1480}
1481
1482/* Add a dump relocation that points a raw pointer back at the dump.
1483
1484 Add a relocation that updates the raw pointer at DUMP_OFFSET in the
1485 dump to point to another object in the dump. The pointer-sized
1486 value at DUMP_OFFSET in the dump file should contain the offset of
1487 the target object relative to the start of the dump. */
1488static void
1489dump_reloc_dump_to_dump_ptr_raw (struct dump_context *ctx,
1490 dump_off dump_offset)
1491{
1492 if (ctx->flags.dump_object_contents)
1493 dump_push (&ctx->dump_relocs,
1494 list2 (make_fixnum (RELOC_DUMP_TO_DUMP_PTR_RAW),
1495 dump_off_to_lisp (dump_offset)));
1496}
1497
1498/* Add a dump relocation that points to a Lisp object in Emacs.
1499
1500 Add a relocation that updates the Lisp_Object at DUMP_OFFSET in the
1501 dump to point to a lisp object in Emacs. The Lisp_Object-sized
1502 value at DUMP_OFFSET in the dump file should contain the offset of
1503 the target object relative to emacs_basis(). TYPE is the type of
1504 Lisp value. */
1505static void
1506dump_reloc_dump_to_emacs_lv (struct dump_context *ctx,
1507 dump_off dump_offset,
1508 enum Lisp_Type type)
1509{
1510 if (!ctx->flags.dump_object_contents)
1511 return;
1512
1513 int reloc_type;
1514 switch (type)
1515 {
1516 case Lisp_String:
1517 case Lisp_Vectorlike:
1518 case Lisp_Cons:
1519 case Lisp_Float:
1520 reloc_type = RELOC_DUMP_TO_EMACS_LV + type;
1521 break;
1522 default:
1523 emacs_abort ();
1524 }
1525
1526 dump_push (&ctx->dump_relocs,
1527 list2 (make_fixnum (reloc_type),
1528 dump_off_to_lisp (dump_offset)));
1529}
1530
1531/* Add an Emacs relocation that copies arbitrary bytes from the dump.
1532
1533 When the dump is loaded, Emacs copies SIZE bytes from OFFSET in
1534 dump to LOCATION in the Emacs data section. This copying happens
1535 after other relocations, so it's all right to, say, copy a
1536 Lisp_Object (since by the time we copy the Lisp_Object, it'll have
1537 been adjusted to account for the location of the running Emacs and
1538 dump file). */
1539static void
1540dump_emacs_reloc_copy_from_dump (struct dump_context *ctx,
1541 dump_off dump_offset,
1542 void* emacs_ptr,
1543 dump_off size)
1544{
1545 eassert (size >= 0);
1546 eassert (size < (1 << EMACS_RELOC_LENGTH_BITS));
1547
1548 if (!ctx->flags.dump_object_contents)
1549 return;
1550
1551 if (size == 0)
1552 return;
1553
1554 eassert (dump_offset >= 0);
1555 dump_push (&ctx->emacs_relocs,
1556 list4 (make_fixnum (RELOC_EMACS_COPY_FROM_DUMP),
1557 dump_off_to_lisp (emacs_offset (emacs_ptr)),
1558 dump_off_to_lisp (dump_offset),
1559 dump_off_to_lisp (size)));
1560}
1561
1562/* Add an Emacs relocation that sets values to arbitrary bytes.
1563
1564 When the dump is loaded, Emacs copies SIZE bytes from the
1565 relocation itself to the adjusted location inside Emacs EMACS_PTR.
1566 SIZE is the number of bytes to copy. See struct emacs_reloc for
1567 the maximum size that this mechanism can support. The value comes
1568 from VALUE_PTR.
1569 */
1570static void
1571dump_emacs_reloc_immediate (struct dump_context *ctx,
1572 const void *emacs_ptr,
1573 const void *value_ptr,
1574 dump_off size)
1575{
1576 if (!ctx->flags.dump_object_contents)
1577 return;
1578
1579 intmax_t value = 0;
1580 eassert (size <= sizeof (value));
1581 memcpy (&value, value_ptr, size);
1582 dump_push (&ctx->emacs_relocs,
1583 list4 (make_fixnum (RELOC_EMACS_IMMEDIATE),
1584 dump_off_to_lisp (emacs_offset (emacs_ptr)),
1585 intmax_t_to_lisp (value),
1586 dump_off_to_lisp (size)));
1587}
1588
1589#define DEFINE_EMACS_IMMEDIATE_FN(fnname, type) \
1590 static void \
1591 fnname (struct dump_context *ctx, \
1592 const type *emacs_ptr, \
1593 type value) \
1594 { \
1595 dump_emacs_reloc_immediate ( \
1596 ctx, emacs_ptr, &value, sizeof (value)); \
1597 }
1598
1599DEFINE_EMACS_IMMEDIATE_FN (dump_emacs_reloc_immediate_lv, Lisp_Object);
1600DEFINE_EMACS_IMMEDIATE_FN (dump_emacs_reloc_immediate_ptrdiff_t, ptrdiff_t);
1601DEFINE_EMACS_IMMEDIATE_FN (dump_emacs_reloc_immediate_emacs_int, EMACS_INT);
1602DEFINE_EMACS_IMMEDIATE_FN (dump_emacs_reloc_immediate_int, int);
1603DEFINE_EMACS_IMMEDIATE_FN (dump_emacs_reloc_immediate_bool, bool);
1604
1605/* Add an emacs relocation that makes a raw pointer in Emacs point
1606 into the dump. */
1607static void
1608dump_emacs_reloc_to_dump_ptr_raw (struct dump_context *ctx,
1609 const void* emacs_ptr,
1610 dump_off dump_offset)
1611{
1612 if (!ctx->flags.dump_object_contents)
1613 return;
1614
1615 dump_push (&ctx->emacs_relocs,
1616 list3 (make_fixnum (RELOC_EMACS_DUMP_PTR_RAW),
1617 dump_off_to_lisp (emacs_offset (emacs_ptr)),
1618 dump_off_to_lisp (dump_offset)));
1619}
1620
1621/* Add an emacs relocation that points into the dump.
1622
1623 When the dump is loaded, the Lisp_Object at EMACS_ROOT in Emacs to
1624 point to VALUE. VALUE can be any Lisp value; this function
1625 automatically queues the value for dumping if necessary. */
1626static void
1627dump_emacs_reloc_to_lv (struct dump_context *ctx,
1628 Lisp_Object *emacs_ptr,
1629 Lisp_Object value)
1630{
1631 if (dump_object_self_representing_p (value))
1632 dump_emacs_reloc_immediate_lv (ctx, emacs_ptr, value);
1633 else
1634 {
1635 if (ctx->flags.dump_object_contents)
1636 /* Conditionally use RELOC_EMACS_EMACS_LV or
1637 RELOC_EMACS_DUMP_LV depending on where the target object
1638 lives. We could just have decode_emacs_reloc pick the
1639 right type, but we might as well maintain the invariant
1640 that the types on ctx->emacs_relocs correspond to the types
1641 of emacs_relocs we actually emit. */
1642 dump_push (
1643 &ctx->emacs_relocs,
1644 list3 (make_fixnum (dump_object_emacs_ptr (value)
1645 ? RELOC_EMACS_EMACS_LV
1646 : RELOC_EMACS_DUMP_LV),
1647 dump_off_to_lisp (emacs_offset (emacs_ptr)),
1648 value));
1649 dump_enqueue_object (ctx, value, WEIGHT_NONE);
1650 }
1651}
1652
1653/* Add an emacs relocation that makes a raw pointer in Emacs point
1654 back into the Emacs image. */
1655static void
1656dump_emacs_reloc_to_emacs_ptr_raw (struct dump_context *ctx,
1657 void* emacs_ptr,
1658 void *target_emacs_ptr)
1659{
1660 if (!ctx->flags.dump_object_contents)
1661 return;
1662
1663 dump_push (&ctx->emacs_relocs,
1664 list3 (make_fixnum (RELOC_EMACS_EMACS_PTR_RAW),
1665 dump_off_to_lisp (emacs_offset (emacs_ptr)),
1666 dump_off_to_lisp (emacs_offset (target_emacs_ptr))));
1667}
1668
1669/* Add an Emacs relocation that makes a raw pointer in Emacs point to
1670 a different part of Emacs. */
1671
1672enum dump_fixup_type
1673 {
1674 DUMP_FIXUP_LISP_OBJECT,
1675 DUMP_FIXUP_LISP_OBJECT_RAW,
1676 DUMP_FIXUP_PTR_DUMP_RAW,
1677 DUMP_FIXUP_BIGNUM_DATA,
1678 };
1679
1680enum dump_lv_fixup_type
1681 {
1682 LV_FIXUP_LISP_OBJECT,
1683 LV_FIXUP_RAW_POINTER,
1684 };
1685
1686/* Make something in the dump point to a lisp object.
1687
1688 CTX is a dump context. DUMP_OFFSET is the location in the dump to
1689 fix. VALUE is the object to which the location in the dump
1690 should point.
1691
1692 If FIXUP_SUBTYPE is LV_FIXUP_LISP_OBJECT, we expect a Lisp_Object
1693 at DUMP_OFFSET. If it's LV_FIXUP_RAW_POINTER, we expect a pointer.
1694 */
1695static void
1696dump_remember_fixup_lv (struct dump_context *ctx,
1697 dump_off dump_offset,
1698 Lisp_Object value,
1699 enum dump_lv_fixup_type fixup_subtype)
1700{
1701 if (!ctx->flags.dump_object_contents)
1702 return;
1703
1704 dump_push (&ctx->fixups,
1705 list3 (
1706 make_fixnum (fixup_subtype == LV_FIXUP_LISP_OBJECT
1707 ? DUMP_FIXUP_LISP_OBJECT
1708 : DUMP_FIXUP_LISP_OBJECT_RAW),
1709 dump_off_to_lisp (dump_offset),
1710 value));
1711}
1712
1713/* Remember to fix up the dump file such that the pointer-sized value
1714 at DUMP_OFFSET points to NEW_DUMP_OFFSET in the dump file and to
1715 its absolute address at runtime. */
1716static void
1717dump_remember_fixup_ptr_raw (struct dump_context *ctx,
1718 dump_off dump_offset,
1719 dump_off new_dump_offset)
1720{
1721 if (!ctx->flags.dump_object_contents)
1722 return;
1723
1724 /* We should not be generating relocations into the
1725 to-be-copied-into-Emacs dump region. */
1726 eassert (ctx->header.discardable_start == 0 ||
1727 new_dump_offset < ctx->header.discardable_start ||
1728 (ctx->header.cold_start != 0 &&
1729 new_dump_offset >= ctx->header.cold_start));
1730
1731 dump_push (&ctx->fixups,
1732 list3 (
1733 make_fixnum (DUMP_FIXUP_PTR_DUMP_RAW),
1734 dump_off_to_lisp (dump_offset),
1735 dump_off_to_lisp (new_dump_offset)));
1736}
1737
1738static void
1739dump_root_visitor (Lisp_Object *root_ptr, enum gc_root_type type, void *data)
1740{
1741 struct dump_context *ctx = data;
1742 Lisp_Object value = *root_ptr;
1743 if (type == GC_ROOT_C_SYMBOL)
1744 {
1745 eassert (dump_builtin_symbol_p (value));
1746 /* Remember to dump the object itself later along with all the
1747 rest of the copied-to-Emacs objects. */
1748 DUMP_SET_REFERRER (ctx, build_string ("built-in symbol list"));
1749 dump_enqueue_object (ctx, value, WEIGHT_NONE);
1750 DUMP_CLEAR_REFERRER (ctx);
1751 }
1752 else
1753 {
1754 if (type == GC_ROOT_STATICPRO)
1755 Fputhash (dump_off_to_lisp (emacs_offset (root_ptr)),
1756 Qt,
1757 ctx->staticpro_table);
1758 if (root_ptr != &Vinternal_interpreter_environment)
1759 {
1760 DUMP_SET_REFERRER (ctx, dump_ptr_referrer ("emacs root", root_ptr));
1761 dump_emacs_reloc_to_lv (ctx, root_ptr, *root_ptr);
1762 DUMP_CLEAR_REFERRER (ctx);
1763 }
1764 }
1765}
1766
1767/* Kick off the dump process by queuing up the static GC roots. */
1768static void
1769dump_roots (struct dump_context *ctx)
1770{
1771 struct gc_root_visitor visitor;
1772 memset (&visitor, 0, sizeof (visitor));
1773 visitor.visit = dump_root_visitor;
1774 visitor.data = ctx;
1775 visit_static_gc_roots (visitor);
1776}
1777
1778static dump_off
1779field_relpos (const void *in_start, const void *in_field)
1780{
1781 ptrdiff_t in_start_val = (ptrdiff_t) in_start;
1782 ptrdiff_t in_field_val = (ptrdiff_t) in_field;
1783 eassert (in_start_val <= in_field_val);
1784 ptrdiff_t relpos = in_field_val - in_start_val;
1785 eassert (relpos < 1024); /* Sanity check. */
1786 return (dump_off) relpos;
1787}
1788
1789static void
1790cpyptr (void *out, const void *in)
1791{
1792 memcpy (out, in, sizeof (void *));
1793}
1794
1795/* Convenience macro for regular assignment. */
1796#define DUMP_FIELD_COPY(out, in, name) \
1797 do \
1798 { \
1799 (out)->name = (in)->name; \
1800 } \
1801 while (0)
1802
1803static void
1804dump_field_lv_or_rawptr (struct dump_context *ctx,
1805 void *out,
1806 const void *in_start,
1807 const void *in_field,
1808 /* opt */ const enum Lisp_Type *ptr_raw_type,
1809 struct link_weight weight)
1810{
1811 eassert (ctx->obj_offset > 0);
1812
1813 Lisp_Object value;
1814 dump_off relpos = field_relpos (in_start, in_field);
1815 void *out_field = (char *) out + relpos;
1816 bool is_ptr_raw = (ptr_raw_type != NULL);
1817
1818 if (!is_ptr_raw)
1819 {
1820 memcpy (&value, in_field, sizeof (value));
1821 if (dump_object_self_representing_p (value))
1822 {
1823 memcpy (out_field, &value, sizeof (value));
1824 return;
1825 }
1826 }
1827 else
1828 {
1829 void *ptrval;
1830 cpyptr (&ptrval, in_field);
1831 if (ptrval == NULL)
1832 return; /* Nothing to do. */
1833 switch (*ptr_raw_type)
1834 {
1835 case Lisp_Symbol:
1836 value = make_lisp_symbol (ptrval);
1837 break;
1838 case Lisp_String:
1839 case Lisp_Vectorlike:
1840 case Lisp_Cons:
1841 case Lisp_Float:
1842 value = make_lisp_ptr (ptrval, *ptr_raw_type);
1843 break;
1844 default:
1845 emacs_abort ();
1846 }
1847 }
1848
1849 /* Now value is the Lisp_Object to which we want to point whether or
1850 not the field is a raw pointer (in which case we just synthesized
1851 the Lisp_Object outselves) or a Lisp_Object (in which case we
1852 just copied the thing). Add a fixup or relocation. */
1853
1854 intptr_t out_value;
1855 dump_off out_field_offset = ctx->obj_offset + relpos;
1856 dump_off target_offset = dump_recall_object (ctx, value);
1857 if (DANGEROUS &&
1858 target_offset > 0 && dump_object_emacs_ptr (value) == NULL)
1859 {
1860 /* We've already dumped the referenced object, so we can emit
1861 the value and a relocation directly instead of indirecting
1862 through a fixup. */
1863 out_value = target_offset;
1864 if (is_ptr_raw)
1865 dump_reloc_dump_to_dump_ptr_raw (ctx, out_field_offset);
1866 else
1867 dump_reloc_dump_to_dump_lv (ctx, out_field_offset, XTYPE (value));
1868 }
1869 else
1870 {
1871 /* We don't know about the target object yet, so add a fixup.
1872 When we process the fixup, we'll have dumped the target
1873 object. */
1874 out_value = (intptr_t) 0xDEADF00D;
1875 dump_remember_fixup_lv (ctx,
1876 out_field_offset,
1877 value,
1878 ( is_ptr_raw
1879 ? LV_FIXUP_RAW_POINTER
1880 : LV_FIXUP_LISP_OBJECT ));
1881 dump_enqueue_object (ctx, value, weight);
1882 }
1883
1884 memcpy (out_field, &out_value, sizeof (out_value));
1885}
1886
1887/* Set a pointer field on an output object during dump.
1888
1889 CTX is the dump context. OFFSET is the offset at which the current
1890 object starts. OUT is a pointer to the dump output object.
1891 IN_START is the start of the current Emacs object. IN_FIELD is a
1892 pointer to the field in that object. TYPE is the type of pointer
1893 to which IN_FIELD points.
1894 */
1895static void
1896dump_field_lv_rawptr (struct dump_context *ctx,
1897 void *out,
1898 const void *in_start,
1899 const void *in_field,
1900 enum Lisp_Type type,
1901 struct link_weight weight)
1902{
1903 dump_field_lv_or_rawptr (ctx, out, in_start, in_field, &type, weight);
1904}
1905
1906/* Set a Lisp_Object field on an output object during dump.
1907
1908 CTX is a dump context. OFFSET is the offset at which the current
1909 object starts. OUT is a pointer to the dump output object.
1910 IN_START is the start of the current Emacs object. IN_FIELD is a
1911 pointer to a Lisp_Object field in that object.
1912
1913 Arrange for the dump to contain fixups and relocations such that,
1914 at load time, the given field of the output object contains a valid
1915 Lisp_Object pointing to the same notional object that *IN_FIELD
1916 contains now.
1917
1918 See idomatic usage below. */
1919static void
1920dump_field_lv (struct dump_context *ctx,
1921 void *out,
1922 const void *in_start,
1923 const Lisp_Object *in_field,
1924 struct link_weight weight)
1925{
1926 dump_field_lv_or_rawptr (ctx, out, in_start, in_field, NULL, weight);
1927}
1928
1929/* Note that we're going to add a manual fixup for the given field
1930 later. */
1931static void
1932dump_field_fixup_later (struct dump_context *ctx,
1933 void *out,
1934 const void *in_start,
1935 const void *in_field)
1936{
1937 // TODO: more error checking
1938 (void) field_relpos (in_start, in_field);
1939}
1940
1941/* Mark an output object field, which is as wide as a poiner, as being
1942 fixed up to point to a specific offset in the dump. */
1943static void
1944dump_field_ptr_to_dump_offset (struct dump_context *ctx,
1945 void *out,
1946 const void *in_start,
1947 const void *in_field,
1948 dump_off target_dump_offset)
1949{
1950 eassert (ctx->obj_offset > 0);
1951 if (!ctx->flags.dump_object_contents)
1952 return;
1953
1954 dump_off relpos = field_relpos (in_start, in_field);
1955 dump_reloc_dump_to_dump_ptr_raw (ctx, ctx->obj_offset + relpos);
1956 intptr_t outval = target_dump_offset;
1957 memcpy ((char*) out + relpos, &outval, sizeof (outval));
1958}
1959
1960/* Mark a field as pointing to a place inside Emacs.
1961
1962 CTX is the dump context. OUT points to the out-object for the
1963 current dump function. IN_START points to the start of the object
1964 being dumped. IN_FIELD points to the field inside the object being
1965 dumped that we're dumping. The contents of this field (which
1966 should be as wide as a pointer) are the Emacs pointer to dump.
1967
1968 */
1969static void
1970dump_field_emacs_ptr (struct dump_context *ctx,
1971 void *out,
1972 const void *in_start,
1973 const void *in_field)
1974{
1975 eassert (ctx->obj_offset > 0);
1976 if (!ctx->flags.dump_object_contents)
1977 return;
1978
1979 dump_off relpos = field_relpos (in_start, in_field);
1980 void *abs_emacs_ptr;
1981 cpyptr (&abs_emacs_ptr, in_field);
1982 intptr_t rel_emacs_ptr = 0;
1983 if (abs_emacs_ptr)
1984 {
1985 rel_emacs_ptr = emacs_offset ((void *)abs_emacs_ptr);
1986 dump_reloc_dump_to_emacs_ptr_raw (ctx, ctx->obj_offset + relpos);
1987 }
1988 cpyptr ((char*) out + relpos, &rel_emacs_ptr);
1989}
1990
1991static void
1992_dump_object_start_pseudovector (
1993 struct dump_context *ctx,
1994 union vectorlike_header *out_hdr,
1995 const union vectorlike_header *in_hdr)
1996{
1997 eassert (in_hdr->size & PSEUDOVECTOR_FLAG);
1998 ptrdiff_t vec_size = vectorlike_nbytes (in_hdr);
1999 dump_object_start (ctx, out_hdr, (dump_off) vec_size);
2000 *out_hdr = *in_hdr;
2001}
2002
2003/* Need a macro for alloca. */
2004#define START_DUMP_PVEC(ctx, hdr, type, out) \
2005 const union vectorlike_header *_in_hdr = (hdr); \
2006 type *out = alloca (vectorlike_nbytes (_in_hdr)); \
2007 _dump_object_start_pseudovector (ctx, &out->header, _in_hdr)
2008
2009static dump_off
2010finish_dump_pvec (struct dump_context *ctx,
2011 union vectorlike_header *out_hdr)
2012{
2013 ALLOW_IMPLICIT_CONVERSION;
2014 return dump_object_finish (ctx, out_hdr, vectorlike_nbytes (out_hdr));
2015 DISALLOW_IMPLICIT_CONVERSION;
2016}
2017
2018static void
2019dump_pseudovector_lisp_fields (
2020 struct dump_context *ctx,
2021 union vectorlike_header *out_hdr,
2022 const union vectorlike_header *in_hdr)
2023{
2024 const struct Lisp_Vector *in = (const struct Lisp_Vector *) in_hdr;
2025 struct Lisp_Vector *out = (struct Lisp_Vector *) out_hdr;
2026 ptrdiff_t size = in->header.size;
2027 eassert (size & PSEUDOVECTOR_FLAG);
2028 size &= PSEUDOVECTOR_SIZE_MASK;
2029 for (ptrdiff_t i = 0; i < size; ++i)
2030 dump_field_lv (ctx, out, in, &in->contents[i], WEIGHT_STRONG);
2031}
2032
2033static dump_off
2034dump_cons (struct dump_context *ctx, const struct Lisp_Cons *cons)
2035{
2036#if CHECK_STRUCTS && !defined (HASH_Lisp_Cons_00EEE63F67)
2037# error "Lisp_Cons changed. See CHECK_STRUCTS comment."
2038#endif
2039 struct Lisp_Cons out;
2040 dump_object_start (ctx, &out, sizeof (out));
2041 dump_field_lv (ctx, &out, cons, &cons->u.s.car, WEIGHT_STRONG);
2042 dump_field_lv (ctx, &out, cons, &cons->u.s.u.cdr, WEIGHT_NORMAL);
2043 return dump_object_finish (ctx, &out, sizeof (out));
2044}
2045
2046static dump_off
2047dump_interval_tree (struct dump_context *ctx,
2048 INTERVAL tree,
2049 dump_off parent_offset)
2050{
2051#if CHECK_STRUCTS && !defined (HASH_interval_9110163DA0)
2052# error "interval changed. See CHECK_STRUCTS comment."
2053#endif
2054 // TODO: output tree breadth-first?
2055 struct interval out;
2056 dump_object_start (ctx, &out, sizeof (out));
2057 DUMP_FIELD_COPY (&out, tree, total_length);
2058 DUMP_FIELD_COPY (&out, tree, position);
2059 if (tree->left)
2060 dump_field_fixup_later (ctx, &out, tree, &tree->left);
2061 if (tree->right)
2062 dump_field_fixup_later (ctx, &out, tree, &tree->right);
2063 if (!tree->up_obj)
2064 {
2065 eassert (parent_offset != 0);
2066 dump_field_ptr_to_dump_offset (
2067 ctx, &out,
2068 tree, &tree->up.interval,
2069 parent_offset);
2070 }
2071 else
2072 dump_field_lv (ctx, &out, tree, &tree->up.obj, WEIGHT_STRONG);
2073 DUMP_FIELD_COPY (&out, tree, up_obj);
2074 eassert (tree->gcmarkbit == 0);
2075 DUMP_FIELD_COPY (&out, tree, write_protect);
2076 DUMP_FIELD_COPY (&out, tree, visible);
2077 DUMP_FIELD_COPY (&out, tree, front_sticky);
2078 DUMP_FIELD_COPY (&out, tree, rear_sticky);
2079 dump_field_lv (ctx, &out, tree, &tree->plist, WEIGHT_STRONG);
2080 dump_off offset = dump_object_finish (ctx, &out, sizeof (out));
2081 if (tree->left)
2082 dump_remember_fixup_ptr_raw (
2083 ctx,
2084 offset + dump_offsetof (struct interval, left),
2085 dump_interval_tree (ctx, tree->left, offset));
2086 if (tree->right)
2087 dump_remember_fixup_ptr_raw (
2088 ctx,
2089 offset + dump_offsetof (struct interval, right),
2090 dump_interval_tree (ctx, tree->right, offset));
2091 return offset;
2092}
2093
2094static dump_off
2095dump_string (struct dump_context *ctx, const struct Lisp_String *string)
2096{
2097#if CHECK_STRUCTS && !defined (HASH_Lisp_Symbol_60EA1E748E)
2098# error "Lisp_String changed. See CHECK_STRUCTS comment."
2099#endif
2100 /* If we have text properties, write them _after_ the string so that
2101 at runtime, the prefetcher and cache will DTRT. (We access the
2102 string before its properties.).
2103
2104 There's special code to dump string data contiguously later on.
2105 we seldom write to string data and never relocate it, so lumping
2106 it together at the end of the dump saves on COW faults.
2107
2108 If, however, the string's size_byte field is -1, the string data
2109 is actually a pointer to Emacs data segment, so we can do even
2110 better by emitting a relocation instead of bothering to copy the
2111 string data. */
2112 struct Lisp_String out;
2113 dump_object_start (ctx, &out, sizeof (out));
2114 DUMP_FIELD_COPY (&out, string, u.s.size);
2115 DUMP_FIELD_COPY (&out, string, u.s.size_byte);
2116 if (string->u.s.intervals)
2117 dump_field_fixup_later (ctx, &out, string, &string->u.s.intervals);
2118
2119 if (string->u.s.size_byte == -2)
2120 /* String literal in Emacs rodata. */
2121 dump_field_emacs_ptr (ctx, &out, string, &string->u.s.data);
2122 else
2123 {
2124 dump_field_fixup_later (ctx, &out, string, &string->u.s.data);
2125 dump_remember_cold_op (ctx,
2126 COLD_OP_STRING,
2127 make_lisp_ptr ((void*) string, Lisp_String));
2128 }
2129
2130 dump_off offset = dump_object_finish (ctx, &out, sizeof (out));
2131 if (string->u.s.intervals)
2132 dump_remember_fixup_ptr_raw (
2133 ctx,
2134 offset + dump_offsetof (struct Lisp_String, u.s.intervals),
2135 dump_interval_tree (ctx, string->u.s.intervals, 0));
2136
2137 return offset;
2138}
2139
2140static dump_off
2141dump_marker (struct dump_context *ctx, const struct Lisp_Marker *marker)
2142{
2143#if CHECK_STRUCTS && !defined (HASH_Lisp_Marker_642DBAF866)
2144# error "Lisp_Marker changed. See CHECK_STRUCTS comment."
2145#endif
2146
2147 START_DUMP_PVEC (ctx, &marker->header, struct Lisp_Marker, out);
2148 dump_pseudovector_lisp_fields (ctx, &out->header, &marker->header);
2149 DUMP_FIELD_COPY (out, marker, need_adjustment);
2150 DUMP_FIELD_COPY (out, marker, insertion_type);
2151 if (marker->buffer)
2152 {
2153 dump_field_lv_rawptr (
2154 ctx, out,
2155 marker, &marker->buffer,
2156 Lisp_Vectorlike,
2157 WEIGHT_NORMAL);
2158 dump_field_lv_rawptr (
2159 ctx, out,
2160 marker, &marker->next,
2161 Lisp_Vectorlike,
2162 WEIGHT_STRONG);
2163 DUMP_FIELD_COPY (out, marker, charpos);
2164 DUMP_FIELD_COPY (out, marker, bytepos);
2165 }
2166 return finish_dump_pvec (ctx, &out->header);
2167}
2168
2169static dump_off
2170dump_overlay (struct dump_context *ctx, const struct Lisp_Overlay *overlay)
2171{
2172#if CHECK_STRUCTS && !defined (HASH_Lisp_Overlay_72EADA9882)
2173# error "Lisp_Overlay changed. See CHECK_STRUCTS comment."
2174#endif
2175 START_DUMP_PVEC (ctx, &overlay->header, struct Lisp_Overlay, out);
2176 dump_pseudovector_lisp_fields (ctx, &out->header, &overlay->header);
2177 dump_field_lv_rawptr (ctx, out, overlay, &overlay->next,
2178 Lisp_Vectorlike, WEIGHT_STRONG);
2179 return finish_dump_pvec (ctx, &out->header);
2180}
2181
2182static void
2183dump_field_finalizer_ref (struct dump_context *ctx,
2184 void *out,
2185 const struct Lisp_Finalizer *finalizer,
2186 struct Lisp_Finalizer *const *field)
2187{
2188 if (*field == &finalizers || *field == &doomed_finalizers)
2189 dump_field_emacs_ptr (ctx, out, finalizer, field);
2190 else
2191 dump_field_lv_rawptr (ctx, out, finalizer, field,
2192 Lisp_Vectorlike,
2193 WEIGHT_NORMAL);
2194}
2195
2196static dump_off
2197dump_finalizer (struct dump_context *ctx,
2198 const struct Lisp_Finalizer *finalizer)
2199{
2200#if CHECK_STRUCTS && !defined (HASH_Lisp_Finalizer_D58E647CB8)
2201# error "Lisp_Finalizer changed. See CHECK_STRUCTS comment."
2202#endif
2203 START_DUMP_PVEC (ctx, &finalizer->header, struct Lisp_Finalizer, out);
2204 /* Do _not_ call dump_pseudovector_lisp_fields here: we dump the
2205 only Lisp field, finalizer->function, manually, so we can give it
2206 a low weight. */
2207 dump_field_lv (ctx, &out, finalizer, &finalizer->function, WEIGHT_NONE);
2208 dump_field_finalizer_ref (ctx, &out, finalizer, &finalizer->prev);
2209 dump_field_finalizer_ref (ctx, &out, finalizer, &finalizer->next);
2210 return finish_dump_pvec (ctx, &out->header);
2211}
2212
2213struct bignum_reload_info
2214{
2215 dump_off data_location;
2216 dump_off nlimbs;
2217};
2218
2219static dump_off
2220dump_bignum (struct dump_context *ctx, Lisp_Object object)
2221{
2222#if CHECK_STRUCTS && !defined (HASH_Lisp_Bignum_661945DE2B)
2223# error "Lisp_Bignum changed. See CHECK_STRUCTS comment."
2224#endif
2225 const struct Lisp_Bignum *bignum = XBIGNUM (object);
2226 START_DUMP_PVEC (ctx, &bignum->header, struct Lisp_Bignum, out);
2227 verify (sizeof (out->value) >= sizeof (struct bignum_reload_info));
2228 dump_field_fixup_later (ctx, out, bignum, &bignum->value);
2229 dump_off bignum_offset = finish_dump_pvec (ctx, &out->header);
2230 if (ctx->flags.dump_object_contents)
2231 {
2232 /* Export the bignum into a blob in the cold section. */
2233 dump_remember_cold_op (ctx, COLD_OP_BIGNUM, object);
2234
2235 /* Write the offset of that exported blob here. */
2236 dump_off value_offset =
2237 bignum_offset +
2238 (dump_off) offsetof (struct Lisp_Bignum, value);
2239 dump_push (&ctx->fixups,
2240 list3 (
2241 make_fixnum (DUMP_FIXUP_BIGNUM_DATA),
2242 dump_off_to_lisp (value_offset),
2243 object));
2244
2245 /* When we load the dump, slurp the data blob and turn it into a
2246 real bignum. Attach the relocation to the start of the
2247 Lisp_Bignum instead of the actual mpz field so that the
2248 relocation offset is aligned. The relocation-application
2249 code knows to actually advance past the header. */
2250 dump_push (&ctx->dump_relocs,
2251 list2 (make_fixnum (RELOC_BIGNUM),
2252 dump_off_to_lisp (bignum_offset)));
2253 }
2254
2255 return bignum_offset;
2256}
2257
2258static dump_off
2259dump_float (struct dump_context *ctx, const struct Lisp_Float *lfloat)
2260{
2261#if CHECK_STRUCTS && !defined (HASH_Lisp_Float_50A7B216D9)
2262# error "Lisp_Float changed. See CHECK_STRUCTS comment."
2263#endif
2264 eassert (ctx->header.cold_start);
2265 struct Lisp_Float out;
2266 dump_object_start (ctx, &out, sizeof (out));
2267 DUMP_FIELD_COPY (&out, lfloat, u.data);
2268 return dump_object_finish (ctx, &out, sizeof (out));
2269}
2270
2271static dump_off
2272dump_fwd_int (struct dump_context *ctx, const struct Lisp_Intfwd *intfwd)
2273{
2274#if CHECK_STRUCTS && !defined (HASH_Lisp_Intfwd_1225FA32CC)
2275# error "Lisp_Intfwd changed. See CHECK_STRUCTS comment."
2276#endif
2277 dump_emacs_reloc_immediate_emacs_int (ctx, intfwd->intvar, *intfwd->intvar);
2278 struct Lisp_Intfwd out;
2279 dump_object_start (ctx, &out, sizeof (out));
2280 DUMP_FIELD_COPY (&out, intfwd, type);
2281 dump_field_emacs_ptr (ctx, &out, intfwd, &intfwd->intvar);
2282 return dump_object_finish (ctx, &out, sizeof (out));
2283}
2284
2285static dump_off
2286dump_fwd_bool (struct dump_context *ctx, const struct Lisp_Boolfwd *boolfwd)
2287{
2288#if CHECK_STRUCTS && !defined (HASH_Lisp_Boolfwd_0EA1C7ADCC)
2289# error "Lisp_Boolfwd changed. See CHECK_STRUCTS comment."
2290#endif
2291 dump_emacs_reloc_immediate_bool (ctx, boolfwd->boolvar, *boolfwd->boolvar);
2292 struct Lisp_Boolfwd out;
2293 dump_object_start (ctx, &out, sizeof (out));
2294 DUMP_FIELD_COPY (&out, boolfwd, type);
2295 dump_field_emacs_ptr (ctx, &out, boolfwd, &boolfwd->boolvar);
2296 return dump_object_finish (ctx, &out, sizeof (out));
2297}
2298
2299static dump_off
2300dump_fwd_obj (struct dump_context *ctx, const struct Lisp_Objfwd *objfwd)
2301{
2302#if CHECK_STRUCTS && !defined (HASH_Lisp_Objfwd_45D3E513DC)
2303# error "Lisp_Objfwd changed. See CHECK_STRUCTS comment."
2304#endif
2305 if (NILP (Fgethash (dump_off_to_lisp (emacs_offset (objfwd->objvar)),
2306 ctx->staticpro_table,
2307 Qnil)))
2308 dump_emacs_reloc_to_lv (ctx, objfwd->objvar, *objfwd->objvar);
2309 struct Lisp_Objfwd out;
2310 dump_object_start (ctx, &out, sizeof (out));
2311 DUMP_FIELD_COPY (&out, objfwd, type);
2312 dump_field_emacs_ptr (ctx, &out, objfwd, &objfwd->objvar);
2313 return dump_object_finish (ctx, &out, sizeof (out));
2314}
2315
2316static dump_off
2317dump_fwd_buffer_obj (struct dump_context *ctx,
2318 const struct Lisp_Buffer_Objfwd *buffer_objfwd)
2319{
2320#if CHECK_STRUCTS && !defined (HASH_Lisp_Buffer_Objfwd_13CA6B04FC)
2321# error "Lisp_Buffer_Objfwd changed. See CHECK_STRUCTS comment."
2322#endif
2323 struct Lisp_Buffer_Objfwd out;
2324 dump_object_start (ctx, &out, sizeof (out));
2325 DUMP_FIELD_COPY (&out, buffer_objfwd, type);
2326 DUMP_FIELD_COPY (&out, buffer_objfwd, offset);
2327 dump_field_lv (ctx, &out, buffer_objfwd, &buffer_objfwd->predicate,
2328 WEIGHT_NORMAL);
2329 return dump_object_finish (ctx, &out, sizeof (out));
2330}
2331
2332static dump_off
2333dump_fwd_kboard_obj (struct dump_context *ctx,
2334 const struct Lisp_Kboard_Objfwd *kboard_objfwd)
2335{
2336#if CHECK_STRUCTS && !defined (HASH_Lisp_Kboard_Objfwd_CAA7E71069)
2337# error "Lisp_Intfwd changed. See CHECK_STRUCTS comment."
2338#endif
2339 struct Lisp_Kboard_Objfwd out;
2340 dump_object_start (ctx, &out, sizeof (out));
2341 DUMP_FIELD_COPY (&out, kboard_objfwd, type);
2342 DUMP_FIELD_COPY (&out, kboard_objfwd, offset);
2343 return dump_object_finish (ctx, &out, sizeof (out));
2344}
2345
2346static dump_off
2347dump_fwd (struct dump_context *ctx, union Lisp_Fwd *fwd)
2348{
2349#if CHECK_STRUCTS && !defined (HASH_Lisp_Fwd_5227B18E87)
2350# error "Lisp_Fwd changed. See CHECK_STRUCTS comment."
2351#endif
2352#if CHECK_STRUCTS && !defined (HASH_Lisp_Fwd_Type_9CBA6EE55E)
2353# error "Lisp_Fwd_Type changed. See CHECK_STRUCTS comment."
2354#endif
2355 dump_off offset;
2356
2357 switch (XFWDTYPE (fwd))
2358 {
2359 case Lisp_Fwd_Int:
2360 offset = dump_fwd_int (ctx, &fwd->u_intfwd);
2361 break;
2362 case Lisp_Fwd_Bool:
2363 offset = dump_fwd_bool (ctx, &fwd->u_boolfwd);
2364 break;
2365 case Lisp_Fwd_Obj:
2366 offset = dump_fwd_obj (ctx, &fwd->u_objfwd);
2367 break;
2368 case Lisp_Fwd_Buffer_Obj:
2369 offset = dump_fwd_buffer_obj (ctx, &fwd->u_buffer_objfwd);
2370 break;
2371 case Lisp_Fwd_Kboard_Obj:
2372 offset = dump_fwd_kboard_obj (ctx, &fwd->u_kboard_objfwd);
2373 break;
2374 default:
2375 emacs_abort ();
2376 }
2377
2378 return offset;
2379}
2380
2381static dump_off
2382dump_blv (struct dump_context *ctx,
2383 const struct Lisp_Buffer_Local_Value *blv)
2384{
2385#if CHECK_STRUCTS && !defined (HASH_Lisp_Buffer_Local_Value_066F33A92E)
2386# error "Lisp_Buffer_Local_Value changed. See CHECK_STRUCTS comment."
2387#endif
2388 struct Lisp_Buffer_Local_Value out;
2389 dump_object_start (ctx, &out, sizeof (out));
2390 DUMP_FIELD_COPY (&out, blv, local_if_set);
2391 DUMP_FIELD_COPY (&out, blv, found);
2392 if (blv->fwd)
2393 dump_field_fixup_later (ctx, &out, blv, &blv->fwd);
2394 dump_field_lv (ctx, &out, blv, &blv->where, WEIGHT_NORMAL);
2395 dump_field_lv (ctx, &out, blv, &blv->defcell, WEIGHT_STRONG);
2396 dump_field_lv (ctx, &out, blv, &blv->valcell, WEIGHT_STRONG);
2397 dump_off offset = dump_object_finish (ctx, &out, sizeof (out));
2398 if (blv->fwd)
2399 dump_remember_fixup_ptr_raw (
2400 ctx,
2401 offset + dump_offsetof (struct Lisp_Buffer_Local_Value, fwd),
2402 dump_fwd (ctx, blv->fwd));
2403 return offset;
2404}
2405
2406static dump_off
2407dump_recall_symbol_aux (struct dump_context *ctx, Lisp_Object symbol)
2408{
2409 Lisp_Object symbol_aux = ctx->symbol_aux;
2410 if (NILP (symbol_aux))
2411 return 0;
2412 return dump_off_from_lisp (
2413 Fgethash (symbol, symbol_aux, make_fixnum (0)));
2414}
2415
2416static void
2417dump_remember_symbol_aux (struct dump_context *ctx,
2418 Lisp_Object symbol,
2419 dump_off offset)
2420{
2421 Fputhash (symbol, dump_off_to_lisp (offset), ctx->symbol_aux);
2422}
2423
2424static void
2425dump_pre_dump_symbol (
2426 struct dump_context *ctx,
2427 struct Lisp_Symbol *symbol)
2428{
2429 Lisp_Object symbol_lv = make_lisp_symbol (symbol);
2430 eassert (!dump_recall_symbol_aux (ctx, symbol_lv));
2431 DUMP_SET_REFERRER (ctx, symbol_lv);
2432 switch (symbol->u.s.redirect)
2433 {
2434 case SYMBOL_LOCALIZED:
2435 dump_remember_symbol_aux (
2436 ctx,
2437 symbol_lv,
2438 dump_blv (ctx, symbol->u.s.val.blv));
2439 break;
2440 case SYMBOL_FORWARDED:
2441 dump_remember_symbol_aux (
2442 ctx,
2443 symbol_lv,
2444 dump_fwd (ctx, symbol->u.s.val.fwd));
2445 break;
2446 default:
2447 break;
2448 }
2449 DUMP_CLEAR_REFERRER (ctx);
2450}
2451
2452static dump_off
2453dump_symbol (struct dump_context *ctx,
2454 Lisp_Object object,
2455 dump_off offset)
2456{
2457#if CHECK_STRUCTS && !defined (HASH_Lisp_Symbol_60EA1E748E)
2458# error "Lisp_Symbol changed. See CHECK_STRUCTS comment."
2459#endif
2460#if CHECK_STRUCTS && !defined (HASH_symbol_redirect_ADB4F5B113)
2461# error "symbol_redirect changed. See CHECK_STRUCTS comment."
2462#endif
2463
2464 if (ctx->flags.defer_symbols)
2465 {
2466 if (offset != DUMP_OBJECT_ON_SYMBOL_QUEUE)
2467 {
2468 eassert (offset == DUMP_OBJECT_ON_NORMAL_QUEUE ||
2469 offset == DUMP_OBJECT_NOT_SEEN);
2470 DUMP_CLEAR_REFERRER (ctx);
2471 struct dump_flags old_flags = ctx->flags;
2472 ctx->flags.dump_object_contents = false;
2473 ctx->flags.defer_symbols = false;
2474 dump_object (ctx, object);
2475 ctx->flags = old_flags;
2476 DUMP_SET_REFERRER (ctx, object);
2477
2478 offset = DUMP_OBJECT_ON_SYMBOL_QUEUE;
2479 dump_remember_object (ctx, object, offset);
2480 dump_push (&ctx->deferred_symbols, object);
2481 }
2482 return offset;
2483 }
2484
2485 struct Lisp_Symbol *symbol = XSYMBOL (object);
2486 struct Lisp_Symbol out;
2487 dump_object_start (ctx, &out, sizeof (out));
2488 eassert (symbol->u.s.gcmarkbit == 0);
2489 DUMP_FIELD_COPY (&out, symbol, u.s.redirect);
2490 DUMP_FIELD_COPY (&out, symbol, u.s.trapped_write);
2491 DUMP_FIELD_COPY (&out, symbol, u.s.interned);
2492 DUMP_FIELD_COPY (&out, symbol, u.s.declared_special);
2493 DUMP_FIELD_COPY (&out, symbol, u.s.pinned);
2494 dump_field_lv (ctx, &out, symbol, &symbol->u.s.name, WEIGHT_STRONG);
2495 switch (symbol->u.s.redirect)
2496 {
2497 case SYMBOL_PLAINVAL:
2498 dump_field_lv (ctx, &out, symbol, &symbol->u.s.val.value,
2499 WEIGHT_NORMAL);
2500 break;
2501 case SYMBOL_VARALIAS:
2502 dump_field_lv_rawptr (ctx, &out, symbol,
2503 &symbol->u.s.val.alias, Lisp_Symbol,
2504 WEIGHT_NORMAL);
2505 break;
2506 case SYMBOL_LOCALIZED:
2507 dump_field_fixup_later (ctx, &out, symbol, &symbol->u.s.val.blv);
2508 break;
2509 case SYMBOL_FORWARDED:
2510 dump_field_fixup_later (ctx, &out, symbol, &symbol->u.s.val.fwd);
2511 break;
2512 default:
2513 emacs_abort ();
2514 }
2515 dump_field_lv (ctx, &out, symbol, &symbol->u.s.function, WEIGHT_NORMAL);
2516 dump_field_lv (ctx, &out, symbol, &symbol->u.s.plist, WEIGHT_NORMAL);
2517 dump_field_lv_rawptr (ctx, &out, symbol, &symbol->u.s.next, Lisp_Symbol,
2518 WEIGHT_STRONG);
2519
2520 offset = dump_object_finish (ctx, &out, sizeof (out));
2521 dump_off aux_offset;
2522
2523 switch (symbol->u.s.redirect)
2524 {
2525 case SYMBOL_LOCALIZED:
2526 aux_offset = dump_recall_symbol_aux (ctx, make_lisp_symbol (symbol));
2527 dump_remember_fixup_ptr_raw (
2528 ctx,
2529 offset + dump_offsetof (struct Lisp_Symbol, u.s.val.blv),
2530 (aux_offset
2531 ? aux_offset
2532 : dump_blv (ctx, symbol->u.s.val.blv)));
2533 break;
2534 case SYMBOL_FORWARDED:
2535 aux_offset = dump_recall_symbol_aux (ctx, make_lisp_symbol (symbol));
2536 dump_remember_fixup_ptr_raw (
2537 ctx,
2538 offset + dump_offsetof (struct Lisp_Symbol, u.s.val.fwd),
2539 (aux_offset
2540 ? aux_offset
2541 : dump_fwd (ctx, symbol->u.s.val.fwd)));
2542 break;
2543 default:
2544 break;
2545 }
2546 return offset;
2547}
2548
2549static dump_off
2550dump_vectorlike_generic (
2551 struct dump_context *ctx,
2552 const union vectorlike_header *header)
2553{
2554#if CHECK_STRUCTS && !defined (HASH_vectorlike_header_00A5A4BFB2)
2555# error "vectorlike_header changed. See CHECK_STRUCTS comment."
2556#endif
2557 const struct Lisp_Vector *v = (const struct Lisp_Vector *) header;
2558 ptrdiff_t size = header->size;
2559 enum pvec_type pvectype = PSEUDOVECTOR_TYPE (v);
2560 dump_off offset;
2561
2562 if (size & PSEUDOVECTOR_FLAG)
2563 {
2564 /* Assert that the pseudovector contains only Lisp values ---
2565 but see the PVEC_SUB_CHAR_TABLE special case below. We allow
2566 one extra word of non-lisp data when Lisp_Object is shorter
2567 than GCALIGN (e.g., on 32-bit builds) to account for
2568 GCALIGN-enforcing struct padding. We can't distinguish
2569 between padding and some undumpable data member this way, but
2570 we'll count on sizeof(Lisp_Object) >= GCALIGN builds to catch
2571 this class of problem.
2572 */
2573 eassert (
2574 ((size & PSEUDOVECTOR_REST_MASK) >> PSEUDOVECTOR_REST_BITS)
2575 <= (sizeof (Lisp_Object) < GCALIGNMENT) ? 1 : 0);
2576 size &= PSEUDOVECTOR_SIZE_MASK;
2577 }
2578
2579 dump_align_output (ctx, DUMP_ALIGNMENT);
2580 dump_off prefix_start_offset = ctx->offset;
2581
2582 dump_off skip;
2583 if (pvectype == PVEC_SUB_CHAR_TABLE)
2584 {
2585 /* PVEC_SUB_CHAR_TABLE has a special case because it's a
2586 variable-length vector (unlike other pseudovectors, which is
2587 why we handle it here) and has its non-Lisp data _before_ the
2588 variable-length Lisp part. */
2589 const struct Lisp_Sub_Char_Table *sct =
2590 (const struct Lisp_Sub_Char_Table *) header;
2591 struct Lisp_Sub_Char_Table out;
2592 /* Don't use sizeof(out), since that incorporates unwanted
2593 padding. Instead, use the size through the last non-Lisp
2594 field. */
2595 size_t sz = (char*)&out.min_char + sizeof (out.min_char) - (char*)&out;
2596 eassert (sz < DUMP_OFF_MAX);
2597 dump_object_start (ctx, &out, (dump_off) sz);
2598 DUMP_FIELD_COPY (&out, sct, header.size);
2599 DUMP_FIELD_COPY (&out, sct, depth);
2600 DUMP_FIELD_COPY (&out, sct, min_char);
2601 offset = dump_object_finish (ctx, &out, (dump_off) sz);
2602 skip = SUB_CHAR_TABLE_OFFSET;
2603 }
2604 else
2605 {
2606 union vectorlike_header out;
2607 dump_object_start (ctx, &out, sizeof (out));
2608 DUMP_FIELD_COPY (&out, header, size);
2609 offset = dump_object_finish (ctx, &out, sizeof (out));
2610 skip = 0;
2611 }
2612
2613 /* We may have written a non-Lisp vector prefix above. If we have,
2614 pad to the lisp content start with zero, and make sure we didn't
2615 scribble beyond that start. */
2616 dump_off prefix_size = ctx->offset - prefix_start_offset;
2617 eassert (prefix_size > 0);
2618 dump_off skip_start = ptrdiff_t_to_dump_off (
2619 (char*) &v->contents[skip] - (char*) v);
2620 eassert (skip_start >= prefix_size);
2621 dump_write_zero (ctx, skip_start - prefix_size);
2622
2623 /* dump_object_start isn't what records conservative-GC object
2624 starts --- dump_object_1 does --- so the hack below of using
2625 dump_object_start for each vector word doesn't cause GC problems
2626 at runtime. */
2627 struct dump_flags old_flags = ctx->flags;
2628 ctx->flags.pack_objects = true;
2629 for (dump_off i = skip; i < size; ++i)
2630 {
2631 Lisp_Object out;
2632 const Lisp_Object *vslot = &v->contents[i];
2633 /* In the wide case, we're always misaligned. */
2634#ifndef WIDE_EMACS_INT
2635 eassert (ctx->offset % sizeof (out) == 0);
2636#endif
2637 dump_object_start (ctx, &out, sizeof (out));
2638 dump_field_lv (ctx, &out, vslot, vslot, WEIGHT_STRONG);
2639 dump_object_finish (ctx, &out, sizeof (out));
2640 }
2641 ctx->flags = old_flags;
2642 dump_align_output (ctx, DUMP_ALIGNMENT);
2643 return offset;
2644}
2645
2646/* Determine whether the hash table's hash order is stable
2647 across dump and load. If it is, we don't have to trigger
2648 a rehash on access. */
2649static bool
2650dump_hash_table_stable_p (const struct Lisp_Hash_Table *hash)
2651{
2652 bool is_eql = hash->test.hashfn == hashfn_eql;
2653 bool is_equal = hash->test.hashfn == hashfn_equal;
2654 ptrdiff_t size = HASH_TABLE_SIZE (hash);
2655 for (ptrdiff_t i = 0; i < size; ++i)
2656 if (!NILP (HASH_HASH (hash, i)))
2657 {
2658 Lisp_Object key = HASH_KEY (hash, i);
2659 bool key_stable = (dump_builtin_symbol_p (key) ||
2660 FIXNUMP (key) ||
2661 (is_equal && STRINGP (key)) ||
2662 ((is_equal || is_eql) && FLOATP (key)));
2663 if (!key_stable)
2664 return false;
2665 }
2666
2667 return true;
2668}
2669
2670/* Return a list of (KEY . VALUE) pairs in the given hash table. */
2671static Lisp_Object
2672hash_table_contents (Lisp_Object table)
2673{
2674 Lisp_Object contents = Qnil;
2675 struct Lisp_Hash_Table *h = XHASH_TABLE (table);
2676 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
2677 if (!NILP (HASH_HASH (h, i)))
2678 dump_push (&contents, Fcons (HASH_KEY (h, i), HASH_VALUE (h, i)));
2679 return Fnreverse (contents);
2680}
2681
2682/* Copy the given hash table, rehash it, and make sure that we can
2683 look up all the values in the original. */
2684static void
2685check_hash_table_rehash (Lisp_Object table_orig)
2686{
2687 hash_rehash_if_needed (XHASH_TABLE (table_orig));
2688 Lisp_Object table_rehashed = Fcopy_hash_table (table_orig);
2689 eassert (XHASH_TABLE (table_rehashed)->count >= 0);
2690 XHASH_TABLE (table_rehashed)->count *= -1;
2691 eassert (XHASH_TABLE (table_rehashed)->count <= 0);
2692 hash_rehash_if_needed (XHASH_TABLE (table_rehashed));
2693 eassert (XHASH_TABLE (table_rehashed)->count >= 0);
2694 Lisp_Object expected_contents = hash_table_contents (table_orig);
2695 while (!NILP (expected_contents))
2696 {
2697 Lisp_Object key_value_pair = dump_pop (&expected_contents);
2698 Lisp_Object key = XCAR (key_value_pair);
2699 Lisp_Object expected_value = XCDR (key_value_pair);
2700 Lisp_Object found_value = Fgethash (
2701 key,
2702 table_rehashed,
2703 Qdump_emacs_portable__sort_predicate_copied /* arbitrary */);
2704 eassert (EQ (expected_value, found_value));
2705 Fremhash (key, table_rehashed);
2706 }
2707
2708 eassert (EQ (Fhash_table_count (table_rehashed),
2709 make_fixnum (0)));
2710}
2711
2712static dump_off
2713dump_hash_table (struct dump_context *ctx,
2714 Lisp_Object object,
2715 dump_off offset)
2716{
2717#if CHECK_STRUCTS && !defined (HASH_Lisp_Hash_Table_73C9BFB7D1)
2718# error "Lisp_Hash_Table changed. See CHECK_STRUCTS comment."
2719#endif
2720 const struct Lisp_Hash_Table *hash_in = XHASH_TABLE (object);
2721 bool is_stable = dump_hash_table_stable_p (hash_in);
2722 /* If the hash table is likely to be modified in memory (either
2723 because we need to rehash, and thus toggle hash->count, or
2724 because we need to assemble a list of weak tables) punt the hash
2725 table to the end of the dump, where we can lump all such hash
2726 tables together. */
2727 if (!(is_stable || !NILP (hash_in->weak)) &&
2728 ctx->flags.defer_hash_tables)
2729 {
2730 if (offset != DUMP_OBJECT_ON_HASH_TABLE_QUEUE)
2731 {
2732 eassert (offset == DUMP_OBJECT_ON_NORMAL_QUEUE ||
2733 offset == DUMP_OBJECT_NOT_SEEN);
2734 /* We still want to dump the actual keys and values now. */
2735 dump_enqueue_object (ctx, hash_in->key_and_value, WEIGHT_NONE);
2736 /* We'll get to the rest later. */
2737 offset = DUMP_OBJECT_ON_HASH_TABLE_QUEUE;
2738 dump_remember_object (ctx, object, offset);
2739 dump_push (&ctx->deferred_hash_tables, object);
2740 }
2741 return offset;
2742 }
2743
2744 if (PDUMPER_CHECK_REHASHING)
2745 check_hash_table_rehash (make_lisp_ptr ((void*)hash_in, Lisp_Vectorlike));
2746
2747 struct Lisp_Hash_Table hash_munged = *hash_in;
2748 struct Lisp_Hash_Table *hash = &hash_munged;
2749
2750 /* Remember to rehash this hash table on first access. After a
2751 dump reload, the hash table values will have changed, so we'll
2752 need to rebuild the index.
2753
2754 TODO: for EQ and EQL hash tables, it should be possible to rehash
2755 here using the preferred load address of the dump, eliminating
2756 the need to rehash-on-access if we can load the dump where we
2757 want. */
2758 if (hash->count > 0 && !is_stable)
2759 hash->count = -hash->count;
2760
2761 START_DUMP_PVEC (ctx, &hash->header, struct Lisp_Hash_Table, out);
2762 dump_pseudovector_lisp_fields (ctx, &out->header, &hash->header);
2763 /* TODO: dump the hash bucket vectors synchronously here to keep
2764 them as close to the hash table as possible. */
2765 DUMP_FIELD_COPY (out, hash, count);
2766 DUMP_FIELD_COPY (out, hash, next_free);
2767 DUMP_FIELD_COPY (out, hash, pure);
2768 DUMP_FIELD_COPY (out, hash, rehash_threshold);
2769 DUMP_FIELD_COPY (out, hash, rehash_size);
2770 dump_field_lv (ctx, out, hash, &hash->key_and_value, WEIGHT_STRONG);
2771 dump_field_lv (ctx, out, hash, &hash->test.name, WEIGHT_STRONG);
2772 dump_field_lv (ctx, out, hash, &hash->test.user_hash_function,
2773 WEIGHT_STRONG);
2774 dump_field_lv (ctx, out, hash, &hash->test.user_cmp_function,
2775 WEIGHT_STRONG);
2776 dump_field_emacs_ptr (ctx, out, hash, &hash->test.cmpfn);
2777 dump_field_emacs_ptr (ctx, out, hash, &hash->test.hashfn);
2778 eassert (hash->next_weak == NULL);
2779 return finish_dump_pvec (ctx, &out->header);
2780}
2781
2782static dump_off
2783dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer)
2784{
2785#if CHECK_STRUCTS && !defined (HASH_buffer_E8695CAE09)
2786# error "buffer changed. See CHECK_STRUCTS comment."
2787#endif
2788 struct buffer munged_buffer = *in_buffer;
2789 struct buffer *buffer = &munged_buffer;
2790
2791 /* Clear some buffer state for correctness upon load. */
2792 if (buffer->base_buffer == NULL)
2793 buffer->window_count = 0;
2794 else
2795 eassert (buffer->window_count == -1);
2796 buffer->last_selected_window_ = Qnil;
2797 buffer->display_count_ = make_fixnum (0);
2798 buffer->clip_changed = 0;
2799 buffer->last_window_start = -1;
2800 buffer->point_before_scroll_ = Qnil;
2801
2802 dump_off base_offset = 0;
2803 if (buffer->base_buffer)
2804 {
2805 eassert (buffer->base_buffer->base_buffer == NULL);
2806 base_offset = dump_object_for_offset (
2807 ctx,
2808 make_lisp_ptr (buffer->base_buffer, Lisp_Vectorlike));
2809 }
2810
2811 eassert ((base_offset == 0 && buffer->text == &in_buffer->own_text) ||
2812 (base_offset > 0 && buffer->text != &in_buffer->own_text));
2813
2814 START_DUMP_PVEC (ctx, &buffer->header, struct buffer, out);
2815 dump_pseudovector_lisp_fields (ctx, &out->header, &buffer->header);
2816 if (base_offset == 0)
2817 base_offset = ctx->obj_offset;
2818 eassert (base_offset > 0);
2819 if (buffer->base_buffer == NULL)
2820 {
2821 eassert (base_offset == ctx->obj_offset);
2822
2823 if (BUFFER_LIVE_P (buffer))
2824 {
2825 dump_field_fixup_later (ctx, out, buffer, &buffer->own_text.beg);
2826 dump_remember_cold_op (
2827 ctx,
2828 COLD_OP_BUFFER,
2829 make_lisp_ptr ((void*) in_buffer, Lisp_Vectorlike));
2830 }
2831 else
2832 eassert (buffer->own_text.beg == NULL);
2833
2834 DUMP_FIELD_COPY (out, buffer, own_text.gpt);
2835 DUMP_FIELD_COPY (out, buffer, own_text.z);
2836 DUMP_FIELD_COPY (out, buffer, own_text.gpt_byte);
2837 DUMP_FIELD_COPY (out, buffer, own_text.z_byte);
2838 DUMP_FIELD_COPY (out, buffer, own_text.gap_size);
2839 DUMP_FIELD_COPY (out, buffer, own_text.modiff);
2840 DUMP_FIELD_COPY (out, buffer, own_text.chars_modiff);
2841 DUMP_FIELD_COPY (out, buffer, own_text.save_modiff);
2842 DUMP_FIELD_COPY (out, buffer, own_text.overlay_modiff);
2843 DUMP_FIELD_COPY (out, buffer, own_text.compact);
2844 DUMP_FIELD_COPY (out, buffer, own_text.beg_unchanged);
2845 DUMP_FIELD_COPY (out, buffer, own_text.end_unchanged);
2846 DUMP_FIELD_COPY (out, buffer, own_text.unchanged_modified);
2847 DUMP_FIELD_COPY (out, buffer, own_text.overlay_unchanged_modified);
2848 if (buffer->own_text.intervals)
2849 dump_field_fixup_later (ctx, out, buffer, &buffer->own_text.intervals);
2850 dump_field_lv_rawptr (ctx, out, buffer, &buffer->own_text.markers,
2851 Lisp_Vectorlike, WEIGHT_NORMAL);
2852 DUMP_FIELD_COPY (out, buffer, own_text.inhibit_shrinking);
2853 DUMP_FIELD_COPY (out, buffer, own_text.redisplay);
2854 }
2855
2856 eassert (ctx->obj_offset > 0);
2857 dump_remember_fixup_ptr_raw (
2858 ctx,
2859 ctx->obj_offset + dump_offsetof (struct buffer, text),
2860 base_offset + dump_offsetof (struct buffer, own_text));
2861
2862 dump_field_lv_rawptr (ctx, out, buffer, &buffer->next,
2863 Lisp_Vectorlike, WEIGHT_NORMAL);
2864 DUMP_FIELD_COPY (out, buffer, pt);
2865 DUMP_FIELD_COPY (out, buffer, pt_byte);
2866 DUMP_FIELD_COPY (out, buffer, begv);
2867 DUMP_FIELD_COPY (out, buffer, begv_byte);
2868 DUMP_FIELD_COPY (out, buffer, zv);
2869 DUMP_FIELD_COPY (out, buffer, zv_byte);
2870
2871 if (buffer->base_buffer)
2872 {
2873 eassert (ctx->obj_offset != base_offset);
2874 dump_field_ptr_to_dump_offset (
2875 ctx, out, buffer, &buffer->base_buffer,
2876 base_offset);
2877 }
2878
2879 DUMP_FIELD_COPY (out, buffer, indirections);
2880 DUMP_FIELD_COPY (out, buffer, window_count);
2881
2882 memcpy (out->local_flags,
2883 &buffer->local_flags,
2884 sizeof (out->local_flags));
2885 DUMP_FIELD_COPY (out, buffer, modtime);
2886 DUMP_FIELD_COPY (out, buffer, modtime_size);
2887 DUMP_FIELD_COPY (out, buffer, auto_save_modified);
2888 DUMP_FIELD_COPY (out, buffer, display_error_modiff);
2889 DUMP_FIELD_COPY (out, buffer, auto_save_failure_time);
2890 DUMP_FIELD_COPY (out, buffer, last_window_start);
2891
2892 /* Not worth serializing these caches. TODO: really? */
2893 out->newline_cache = NULL;
2894 out->width_run_cache = NULL;
2895 out->bidi_paragraph_cache = NULL;
2896
2897 DUMP_FIELD_COPY (out, buffer, prevent_redisplay_optimizations_p);
2898 DUMP_FIELD_COPY (out, buffer, clip_changed);
2899
2900 dump_field_lv_rawptr (ctx, out, buffer, &buffer->overlays_before,
2901 Lisp_Vectorlike, WEIGHT_NORMAL);
2902
2903 dump_field_lv_rawptr (ctx, out, buffer, &buffer->overlays_after,
2904 Lisp_Vectorlike, WEIGHT_NORMAL);
2905
2906 DUMP_FIELD_COPY (out, buffer, overlay_center);
2907 dump_field_lv (ctx, out, buffer, &buffer->undo_list_,
2908 WEIGHT_STRONG);
2909 dump_off offset = finish_dump_pvec (ctx, &out->header);
2910 if (!buffer->base_buffer && buffer->own_text.intervals)
2911 dump_remember_fixup_ptr_raw (
2912 ctx,
2913 offset + dump_offsetof (struct buffer, own_text.intervals),
2914 dump_interval_tree (ctx, buffer->own_text.intervals, 0));
2915
2916 return offset;
2917}
2918
2919static dump_off
2920dump_bool_vector (struct dump_context *ctx, const struct Lisp_Vector *v)
2921{
2922#if CHECK_STRUCTS && !defined (HASH_Lisp_Vector_3091289B35)
2923# error "Lisp_Vector changed. See CHECK_STRUCTS comment."
2924#endif
2925 /* No relocation needed, so we don't need dump_object_start. */
2926 dump_align_output (ctx, DUMP_ALIGNMENT);
2927 eassert (ctx->offset >= ctx->header.cold_start);
2928 dump_off offset = ctx->offset;
2929 ptrdiff_t nbytes = vector_nbytes ((struct Lisp_Vector *) v);
2930 if (nbytes > DUMP_OFF_MAX)
2931 error ("vector too large");
2932 dump_write (ctx, v, ptrdiff_t_to_dump_off (nbytes));
2933 return offset;
2934}
2935
2936static dump_off
2937dump_subr (struct dump_context *ctx, const struct Lisp_Subr *subr)
2938{
2939#if CHECK_STRUCTS && !defined (HASH_Lisp_Subr_594AB72B54)
2940# error "Lisp_Subr changed. See CHECK_STRUCTS comment."
2941#endif
2942 struct Lisp_Subr out;
2943 dump_object_start (ctx, &out, sizeof (out));
2944 DUMP_FIELD_COPY (&out, subr, header.size);
2945 dump_field_emacs_ptr (ctx, &out, subr, &subr->function.a0);
2946 DUMP_FIELD_COPY (&out, subr, min_args);
2947 DUMP_FIELD_COPY (&out, subr, max_args);
2948 dump_field_emacs_ptr (ctx, &out, subr, &subr->symbol_name);
2949 dump_field_emacs_ptr (ctx, &out, subr, &subr->intspec);
2950 DUMP_FIELD_COPY (&out, subr, doc);
2951 return dump_object_finish (ctx, &out, sizeof (out));
2952}
2953
2954static void
2955fill_pseudovec (union vectorlike_header *header, Lisp_Object item)
2956{
2957 struct Lisp_Vector *v = (struct Lisp_Vector *) header;
2958 eassert (v->header.size & PSEUDOVECTOR_FLAG);
2959 ptrdiff_t size = v->header.size & PSEUDOVECTOR_SIZE_MASK;
2960 for (ptrdiff_t idx = 0; idx < size; idx++)
2961 v->contents[idx] = item;
2962}
2963
2964static dump_off
2965dump_nilled_pseudovec (struct dump_context *ctx,
2966 const union vectorlike_header *in)
2967{
2968 START_DUMP_PVEC (ctx, in, struct Lisp_Vector, out);
2969 fill_pseudovec (&out->header, Qnil);
2970 return finish_dump_pvec (ctx, &out->header);
2971}
2972
2973static dump_off
2974dump_vectorlike (struct dump_context *ctx,
2975 Lisp_Object lv,
2976 dump_off offset)
2977{
2978#if CHECK_STRUCTS && !defined (HASH_pvec_type_549C833A54)
2979# error "pvec_type changed. See CHECK_STRUCTS comment."
2980#endif
2981 const struct Lisp_Vector *v = XVECTOR (lv);
2982 switch (PSEUDOVECTOR_TYPE (v))
2983 {
2984 case PVEC_FONT:
2985 /* There are three kinds of font objects that all use PVEC_FONT,
2986 distinguished by their size. Font specs and entities are
2987 harmless data carriers that we can dump like other Lisp
2988 objects. Fonts themselves are window-system-specific and
2989 need to be recreated on each startup. */
2990 if ((v->header.size & PSEUDOVECTOR_SIZE_MASK) != FONT_SPEC_MAX &&
2991 (v->header.size & PSEUDOVECTOR_SIZE_MASK) != FONT_ENTITY_MAX)
2992 error_unsupported_dump_object(ctx, lv, "font");
2993 FALLTHROUGH;
2994 case PVEC_NORMAL_VECTOR:
2995 case PVEC_COMPILED:
2996 case PVEC_CHAR_TABLE:
2997 case PVEC_SUB_CHAR_TABLE:
2998 case PVEC_RECORD:
2999 offset = dump_vectorlike_generic (ctx, &v->header);
3000 break;
3001 case PVEC_BOOL_VECTOR:
3002 offset = dump_bool_vector(ctx, v);
3003 break;
3004 case PVEC_HASH_TABLE:
3005 offset = dump_hash_table (ctx, lv, offset);
3006 break;
3007 case PVEC_BUFFER:
3008 offset = dump_buffer (ctx, XBUFFER (lv));
3009 break;
3010 case PVEC_SUBR:
3011 offset = dump_subr (ctx, XSUBR (lv));
3012 break;
3013 case PVEC_FRAME:
3014 case PVEC_WINDOW:
3015 case PVEC_PROCESS:
3016 case PVEC_TERMINAL:
3017 offset = dump_nilled_pseudovec (ctx, &v->header);
3018 break;
3019 case PVEC_MARKER:
3020 offset = dump_marker (ctx, XMARKER (lv));
3021 break;
3022 case PVEC_OVERLAY:
3023 offset = dump_overlay (ctx, XOVERLAY (lv));
3024 break;
3025 case PVEC_FINALIZER:
3026 offset = dump_finalizer (ctx, XFINALIZER (lv));
3027 break;
3028 case PVEC_BIGNUM:
3029 offset = dump_bignum (ctx, lv);
3030 break;
3031 case PVEC_WINDOW_CONFIGURATION:
3032 error_unsupported_dump_object (ctx, lv, "window configuration");
3033 case PVEC_OTHER:
3034 error_unsupported_dump_object (ctx, lv, "other?!");
3035 case PVEC_XWIDGET:
3036 error_unsupported_dump_object (ctx, lv, "xwidget");
3037 case PVEC_XWIDGET_VIEW:
3038 error_unsupported_dump_object (ctx, lv, "xwidget view");
3039 case PVEC_MISC_PTR:
3040#ifdef HAVE_MODULES
3041 case PVEC_USER_PTR:
3042#endif
3043 error_unsupported_dump_object (ctx, lv, "smuggled pointers");
3044 case PVEC_THREAD:
3045 if (main_thread_p (v))
3046 {
3047 eassert (dump_object_emacs_ptr (lv));
3048 return DUMP_OBJECT_IS_RUNTIME_MAGIC;
3049 }
3050 error_unsupported_dump_object (ctx, lv, "thread");
3051 case PVEC_MUTEX:
3052 error_unsupported_dump_object (ctx, lv, "mutex");
3053 case PVEC_CONDVAR:
3054 error_unsupported_dump_object (ctx, lv, "condvar");
3055 case PVEC_MODULE_FUNCTION:
3056 error_unsupported_dump_object (ctx, lv, "module function");
3057 default:
3058 error_unsupported_dump_object(ctx, lv, "weird pseudovector");
3059 }
3060
3061 return offset;
3062}
3063
3064/* Add an object to the dump.
3065
3066 CTX is the dump context; OBJECT is the object to add. Normally,
3067 return OFFSET, the location (in bytes, from the start of the dump
3068 file) where we wrote the object. Valid OFFSETs are always greater
3069 than zero.
3070
3071 If we've already dumped an object, return the location where we put
3072 it: dump_object is idempotent.
3073
3074 The object must refer to an actual pointer-ish object of some sort.
3075 Some self-representing objects are immediate values rather than
3076 tagged pointers to Lisp heap structures and so have no individual
3077 representation in the Lisp heap dump.
3078
3079 May also return one of the DUMP_OBJECT_ON_*_QUEUE constants if we
3080 "dumped" the object by remembering to process it specially later.
3081 In this case, we don't have a valid offset.
3082 Call dump_object_for_offset if you need a valid offset for
3083 an object.
3084 */
3085static dump_off
3086dump_object (struct dump_context *ctx, Lisp_Object object)
3087{
3088#if CHECK_STRUCTS && !defined (HASH_Lisp_Type_E2AD97D3F7)
3089# error "Lisp_Type changed. See CHECK_STRUCTS comment."
3090#endif
3091#ifdef ENABLE_CHECKING
3092 /* Vdead is extern only when ENABLE_CHECKING. */
3093 eassert (!EQ (object, Vdead));
3094#endif
3095
3096 dump_off offset = dump_recall_object (ctx, object);
3097 if (offset > 0)
3098 return offset; /* Object already dumped. */
3099
3100 bool cold = BOOL_VECTOR_P (object) || FLOATP (object);
3101 if (cold && ctx->flags.defer_cold_objects)
3102 {
3103 if (offset != DUMP_OBJECT_ON_COLD_QUEUE)
3104 {
3105 eassert (offset == DUMP_OBJECT_ON_NORMAL_QUEUE ||
3106 offset == DUMP_OBJECT_NOT_SEEN);
3107 offset = DUMP_OBJECT_ON_COLD_QUEUE;
3108 dump_remember_object (ctx, object, offset);
3109 dump_remember_cold_op (ctx, COLD_OP_OBJECT, object);
3110 }
3111 return offset;
3112 }
3113
3114 void* obj_in_emacs = dump_object_emacs_ptr (object);
3115 if (obj_in_emacs && ctx->flags.defer_copied_objects)
3116 {
3117 if (offset != DUMP_OBJECT_ON_COPIED_QUEUE)
3118 {
3119 eassert (offset == DUMP_OBJECT_ON_NORMAL_QUEUE ||
3120 offset == DUMP_OBJECT_NOT_SEEN);
3121 /* Even though we're not going to dump this object right
3122 away, we still want to scan and enqueue its
3123 referents. */
3124 struct dump_flags old_flags = ctx->flags;
3125 ctx->flags.dump_object_contents = false;
3126 ctx->flags.defer_copied_objects = false;
3127 dump_object (ctx, object);
3128 ctx->flags = old_flags;
3129
3130 offset = DUMP_OBJECT_ON_COPIED_QUEUE;
3131 dump_remember_object (ctx, object, offset);
3132 dump_push (&ctx->copied_queue, object);
3133 }
3134 return offset;
3135 }
3136
3137 /* Object needs to be dumped. */
3138 DUMP_SET_REFERRER (ctx, object);
3139 switch (XTYPE (object))
3140 {
3141 case Lisp_String:
3142 offset = dump_string (ctx, XSTRING (object));
3143 break;
3144 case Lisp_Vectorlike:
3145 offset = dump_vectorlike (ctx, object, offset);
3146 break;
3147 case Lisp_Symbol:
3148 offset = dump_symbol (ctx, object, offset);
3149 break;
3150 case Lisp_Cons:
3151 offset = dump_cons (ctx, XCONS (object));
3152 break;
3153 case Lisp_Float:
3154 offset = dump_float (ctx, XFLOAT (object));
3155 break;
3156 case_Lisp_Int:
3157 eassert ("should not be dumping int: is self-representing" && 0);
3158 abort ();
3159 default:
3160 emacs_abort ();
3161 }
3162 DUMP_CLEAR_REFERRER (ctx);
3163
3164 /* offset can be < 0 if we've deferred an object. */
3165 if (ctx->flags.dump_object_contents && offset > DUMP_OBJECT_NOT_SEEN)
3166 {
3167 eassert (offset % DUMP_ALIGNMENT == 0);
3168 dump_remember_object (ctx, object, offset);
3169 if (ctx->flags.record_object_starts)
3170 {
3171 eassert (!ctx->flags.pack_objects);
3172 dump_push (&ctx->object_starts,
3173 list2 (dump_off_to_lisp (XTYPE (object)),
3174 dump_off_to_lisp (offset)));
3175 }
3176 }
3177
3178 return offset;
3179}
3180
3181/* Like dump_object(), but assert that we get a valid offset. */
3182static dump_off
3183dump_object_for_offset (struct dump_context *ctx, Lisp_Object object)
3184{
3185 dump_off offset = dump_object (ctx, object);
3186 eassert (offset > 0);
3187 return offset;
3188}
3189
3190static dump_off
3191dump_charset (struct dump_context *ctx, int cs_i)
3192{
3193#if CHECK_STRUCTS && !defined (HASH_charset_317C49E291)
3194# error "charset changed. See CHECK_STRUCTS comment."
3195#endif
3196 dump_align_output (ctx, alignof (int));
3197 const struct charset *cs = charset_table + cs_i;
3198 struct charset out;
3199 dump_object_start (ctx, &out, sizeof (out));
3200 DUMP_FIELD_COPY (&out, cs, id);
3201 DUMP_FIELD_COPY (&out, cs, hash_index);
3202 DUMP_FIELD_COPY (&out, cs, dimension);
3203 memcpy (out.code_space, &cs->code_space, sizeof (cs->code_space));
3204 if (cs->code_space_mask)
3205 dump_field_fixup_later (ctx, &out, cs, &cs->code_space_mask);
3206 DUMP_FIELD_COPY (&out, cs, code_linear_p);
3207 DUMP_FIELD_COPY (&out, cs, iso_chars_96);
3208 DUMP_FIELD_COPY (&out, cs, ascii_compatible_p);
3209 DUMP_FIELD_COPY (&out, cs, supplementary_p);
3210 DUMP_FIELD_COPY (&out, cs, compact_codes_p);
3211 DUMP_FIELD_COPY (&out, cs, unified_p);
3212 DUMP_FIELD_COPY (&out, cs, iso_final);
3213 DUMP_FIELD_COPY (&out, cs, iso_revision);
3214 DUMP_FIELD_COPY (&out, cs, emacs_mule_id);
3215 DUMP_FIELD_COPY (&out, cs, method);
3216 DUMP_FIELD_COPY (&out, cs, min_code);
3217 DUMP_FIELD_COPY (&out, cs, max_code);
3218 DUMP_FIELD_COPY (&out, cs, char_index_offset);
3219 DUMP_FIELD_COPY (&out, cs, min_char);
3220 DUMP_FIELD_COPY (&out, cs, max_char);
3221 DUMP_FIELD_COPY (&out, cs, invalid_code);
3222 memcpy (out.fast_map, &cs->fast_map, sizeof (cs->fast_map));
3223 DUMP_FIELD_COPY (&out, cs, code_offset);
3224 dump_off offset = dump_object_finish (ctx, &out, sizeof (out));
3225 if (cs->code_space_mask)
3226 dump_remember_cold_op (ctx, COLD_OP_CHARSET,
3227 Fcons (dump_off_to_lisp (cs_i),
3228 dump_off_to_lisp (offset)));
3229 return offset;
3230}
3231
3232static dump_off
3233dump_charset_table (struct dump_context *ctx)
3234{
3235 struct dump_flags old_flags = ctx->flags;
3236 ctx->flags.pack_objects = true;
3237 dump_align_output (ctx, DUMP_ALIGNMENT);
3238 dump_off offset = ctx->offset;
3239 for (int i = 0; i < charset_table_used; ++i)
3240 dump_charset (ctx, i);
3241 dump_emacs_reloc_to_dump_ptr_raw (ctx, &charset_table, offset);
3242 ctx->flags = old_flags;
3243 return offset;
3244}
3245
3246static void
3247dump_finalizer_list_head_ptr (struct dump_context *ctx,
3248 struct Lisp_Finalizer **ptr)
3249{
3250 struct Lisp_Finalizer *value = *ptr;
3251 if (value != &finalizers && value != &doomed_finalizers)
3252 dump_emacs_reloc_to_dump_ptr_raw (
3253 ctx, ptr,
3254 dump_object_for_offset (ctx,
3255 make_lisp_ptr (value, Lisp_Vectorlike)));
3256}
3257
3258static void
3259dump_metadata_for_pdumper (struct dump_context *ctx)
3260{
3261 for (int i = 0; i < nr_dump_hooks; ++i)
3262 dump_emacs_reloc_to_emacs_ptr_raw (ctx, &dump_hooks[i], dump_hooks[i]);
3263 dump_emacs_reloc_immediate_int (ctx, &nr_dump_hooks, nr_dump_hooks);
3264
3265 for (int i = 0; i < nr_remembered_data; ++i)
3266 {
3267 dump_emacs_reloc_to_emacs_ptr_raw (
3268 ctx,
3269 &remembered_data[i].mem,
3270 remembered_data[i].mem);
3271 dump_emacs_reloc_immediate_int (
3272 ctx,
3273 &remembered_data[i].sz,
3274 remembered_data[i].sz);
3275 }
3276 dump_emacs_reloc_immediate_int (
3277 ctx,
3278 &nr_remembered_data,
3279 nr_remembered_data);
3280}
3281
3282/* Sort the list of copied objects in CTX. */
3283static void
3284dump_sort_copied_objects (struct dump_context *ctx)
3285{
3286 /* Sort the objects into the order in which they'll appear in the
3287 Emacs: this way, on startup, we'll do both the IO from the dump
3288 file and the copy into Emacs in-order, where prefetch will be
3289 most effective. */
3290 ctx->copied_queue =
3291 Fsort (Fnreverse (ctx->copied_queue),
3292 Qdump_emacs_portable__sort_predicate_copied);
3293}
3294
3295/* Dump parts of copied objects we need at runtime. */
3296static void
3297dump_hot_parts_of_discardable_objects (struct dump_context *ctx)
3298{
3299 Lisp_Object copied_queue = ctx->copied_queue;
3300 while (!NILP (copied_queue))
3301 {
3302 Lisp_Object copied = dump_pop (&copied_queue);
3303 if (SYMBOLP (copied))
3304 {
3305 eassert (dump_builtin_symbol_p (copied));
3306 dump_pre_dump_symbol (ctx, XSYMBOL (copied));
3307 }
3308 }
3309}
3310
3311static void
3312dump_drain_copied_objects (struct dump_context *ctx)
3313{
3314 Lisp_Object copied_queue = ctx->copied_queue;
3315 ctx->copied_queue = Qnil;
3316
3317 struct dump_flags old_flags = ctx->flags;
3318
3319 /* We should have already fully scanned these objects, so assert
3320 that we're not adding more entries to the dump queue. */
3321 ctx->flags.assert_already_seen = true;
3322
3323 /* Now we want to actually dump the copied objects, not just record
3324 them. */
3325 ctx->flags.defer_copied_objects = false;
3326
3327 /* Objects that we memcpy into Emacs shouldn't get object-start
3328 records (which conservative GC looks at): we usually discard this
3329 memory after we're finished memcpying, and even if we don't, the
3330 "real" objects in this section all live in the Emacs image, not
3331 in the dump. */
3332 ctx->flags.record_object_starts = false;
3333
3334 /* Dump the objects and generate a copy relocation for each. Don't
3335 bother trying to reduce the number of copy relocations we
3336 generate: we'll merge adjacent copy relocations upon output.
3337 The overall result is that to the greatest extent possible while
3338 maintaining strictly increasing address order, we copy into Emacs
3339 in nice big chunks. */
3340 while (!NILP (copied_queue))
3341 {
3342 Lisp_Object copied = dump_pop (&copied_queue);
3343 void *optr = dump_object_emacs_ptr (copied);
3344 eassert (optr != NULL);
3345 /* N.B. start_offset is beyond any padding we insert. */
3346 dump_off start_offset = dump_object (ctx, copied);
3347 if (start_offset != DUMP_OBJECT_IS_RUNTIME_MAGIC)
3348 {
3349 dump_off size = ctx->offset - start_offset;
3350 dump_emacs_reloc_copy_from_dump (ctx, start_offset, optr, size);
3351 }
3352 }
3353
3354 ctx->flags = old_flags;
3355}
3356
3357static void
3358dump_cold_string (struct dump_context *ctx, Lisp_Object string)
3359{
3360 /* Dump string contents. */
3361 dump_off string_offset = dump_recall_object (ctx, string);
3362 eassert (string_offset > 0);
3363 if (SBYTES (string) > DUMP_OFF_MAX - 1)
3364 error ("string too large");
3365 dump_off total_size = ptrdiff_t_to_dump_off (SBYTES (string) + 1);
3366 eassert (total_size > 0);
3367 dump_remember_fixup_ptr_raw (
3368 ctx,
3369 string_offset + dump_offsetof (struct Lisp_String, u.s.data),
3370 ctx->offset);
3371 dump_write (ctx, XSTRING (string)->u.s.data, total_size);
3372}
3373
3374static void
3375dump_cold_charset (struct dump_context *ctx, Lisp_Object data)
3376{
3377 /* Dump charset lookup tables. */
3378 ALLOW_IMPLICIT_CONVERSION;
3379 int cs_i = XFIXNUM (XCAR (data));
3380 DISALLOW_IMPLICIT_CONVERSION;
3381 dump_off cs_dump_offset = dump_off_from_lisp (XCDR (data));
3382 dump_remember_fixup_ptr_raw (
3383 ctx,
3384 cs_dump_offset + dump_offsetof (struct charset, code_space_mask),
3385 ctx->offset);
3386 struct charset *cs = charset_table + cs_i;
3387 dump_write (ctx, cs->code_space_mask, 256);
3388}
3389
3390static void
3391dump_cold_buffer (struct dump_context *ctx, Lisp_Object data)
3392{
3393 /* Dump buffer text. */
3394 dump_off buffer_offset = dump_recall_object (ctx, data);
3395 eassert (buffer_offset > 0);
3396 struct buffer *b = XBUFFER (data);
3397 eassert (b->text == &b->own_text);
3398 /* Zero the gap so we don't dump uninitialized bytes. */
3399 memset (BUF_GPT_ADDR (b), 0, BUF_GAP_SIZE (b));
3400 /* See buffer.c for this calculation. */
3401 ptrdiff_t nbytes =
3402 BUF_Z_BYTE (b)
3403 - BUF_BEG_BYTE (b)
3404 + BUF_GAP_SIZE (b)
3405 + 1;
3406 if (nbytes > DUMP_OFF_MAX)
3407 error ("buffer too large");
3408 dump_remember_fixup_ptr_raw (
3409 ctx,
3410 buffer_offset + dump_offsetof (struct buffer, own_text.beg),
3411 ctx->offset);
3412 dump_write (ctx, b->own_text.beg, ptrdiff_t_to_dump_off (nbytes));
3413}
3414
3415static void
3416dump_cold_bignum (struct dump_context *ctx, Lisp_Object object)
3417{
3418 const struct Lisp_Bignum *bignum = XBIGNUM (object);
3419 size_t sz_nlimbs = mpz_size (bignum->value);
3420 eassert (sz_nlimbs < DUMP_OFF_MAX);
3421 dump_align_output (ctx, alignof (mp_limb_t));
3422 dump_off nlimbs = (dump_off) sz_nlimbs;
3423 Lisp_Object descriptor = list2 (
3424 dump_off_to_lisp (ctx->offset),
3425 dump_off_to_lisp ((mpz_sgn (bignum->value) < 0
3426 ? -nlimbs : nlimbs)));
3427 Fputhash (object, descriptor, ctx->bignum_data);
3428 for (size_t i = 0; i < nlimbs; ++i)
3429 {
3430 mp_limb_t limb = mpz_getlimbn (bignum->value, i);
3431 dump_write (ctx, &limb, sizeof (limb));
3432 }
3433}
3434
3435static void
3436dump_drain_cold_data (struct dump_context *ctx)
3437{
3438 Lisp_Object cold_queue = Fnreverse (ctx->cold_queue);
3439 ctx->cold_queue = Qnil;
3440
3441 struct dump_flags old_flags = ctx->flags;
3442
3443 /* We should have already scanned all objects to which our cold
3444 objects refer, so die if an object points to something we haven't
3445 seen. */
3446 ctx->flags.assert_already_seen = true;
3447
3448 /* Actually dump cold objects instead of deferring them. */
3449 ctx->flags.defer_cold_objects = false;
3450
3451 while (!NILP (cold_queue))
3452 {
3453 Lisp_Object item = dump_pop (&cold_queue);
3454 enum cold_op op = (enum cold_op) XFIXNUM (XCAR (item));
3455 Lisp_Object data = XCDR (item);
3456 switch (op)
3457 {
3458 case COLD_OP_STRING:
3459 dump_cold_string (ctx, data);
3460 break;
3461 case COLD_OP_CHARSET:
3462 dump_cold_charset (ctx, data);
3463 break;
3464 case COLD_OP_BUFFER:
3465 dump_cold_buffer (ctx, data);
3466 break;
3467 case COLD_OP_OBJECT:
3468 /* Objects that we can put in the cold section
3469 must not refer to other objects. */
3470 eassert (dump_queue_empty_p (&ctx->dump_queue));
3471 eassert (ctx->flags.dump_object_contents);
3472 dump_object (ctx, data);
3473 eassert (dump_queue_empty_p (&ctx->dump_queue));
3474 break;
3475 case COLD_OP_BIGNUM:
3476 dump_cold_bignum (ctx, data);
3477 break;
3478 default:
3479 emacs_abort ();
3480 }
3481 }
3482
3483 ctx->flags = old_flags;
3484}
3485
3486static void
3487read_ptr_raw_and_lv (const void *mem,
3488 enum Lisp_Type type,
3489 void **out_ptr,
3490 Lisp_Object *out_lv)
3491{
3492 memcpy (out_ptr, mem, sizeof (*out_ptr));
3493 if (*out_ptr != NULL)
3494 {
3495 switch (type)
3496 {
3497 case Lisp_Symbol:
3498 *out_lv = make_lisp_symbol (*out_ptr);
3499 break;
3500 case Lisp_String:
3501 case Lisp_Vectorlike:
3502 case Lisp_Cons:
3503 case Lisp_Float:
3504 *out_lv = make_lisp_ptr (*out_ptr, type);
3505 break;
3506 default:
3507 emacs_abort ();
3508 }
3509 }
3510}
3511
3512/* Enqueue for dumping objects referenced by static non-Lisp_Object
3513 pointers inside Emacs. */
3514static void
3515dump_drain_user_remembered_data_hot (struct dump_context *ctx)
3516{
3517 for (int i = 0; i < nr_remembered_data; ++i)
3518 {
3519 void *mem = remembered_data[i].mem;
3520 int sz = remembered_data[i].sz;
3521 if (sz <= 0)
3522 {
3523 enum Lisp_Type type = -sz;
3524 void *value;
3525 Lisp_Object lv;
3526 read_ptr_raw_and_lv (mem, type, &value, &lv);
3527 if (value != NULL)
3528 {
3529 DUMP_SET_REFERRER (ctx, dump_ptr_referrer ("user data", mem));
3530 dump_enqueue_object (ctx, lv, WEIGHT_NONE);
3531 DUMP_CLEAR_REFERRER (ctx);
3532 }
3533 }
3534 }
3535}
3536
3537/* Dump user-specified non-relocated data. */
3538static void
3539dump_drain_user_remembered_data_cold (struct dump_context *ctx)
3540{
3541 for (int i = 0; i < nr_remembered_data; ++i)
3542 {
3543 void *mem = remembered_data[i].mem;
3544 int sz = remembered_data[i].sz;
3545 if (sz > 0)
3546 {
3547 /* Scalar: try to inline the value into the relocation if
3548 it's small enough; if it's bigger than we can fit in a
3549 relocation, we have to copy the data into the dump proper
3550 and emit a copy relocation. */
3551 if (sz <= sizeof (intmax_t))
3552 dump_emacs_reloc_immediate (ctx, mem, mem, sz);
3553 else
3554 {
3555 dump_emacs_reloc_copy_from_dump (ctx, ctx->offset, mem, sz);
3556 dump_write (ctx, mem, sz);
3557 }
3558 }
3559 else
3560 {
3561 /* *mem is a raw pointer to a Lisp object of some sort.
3562 The object to which it points should have already been
3563 dumped by dump_drain_user_remembered_data_hot. */
3564 void *value;
3565 Lisp_Object lv;
3566 enum Lisp_Type type = -sz;
3567 read_ptr_raw_and_lv (mem, type, &value, &lv);
3568 if (value == NULL)
3569 /* We can't just ignore NULL: the variable might have
3570 transitioned from non-NULL to NULL, and we want to
3571 record this fact. */
3572 dump_emacs_reloc_immediate_ptrdiff_t (ctx, mem, 0);
3573 else
3574 {
3575 if (dump_object_emacs_ptr (lv) != NULL)
3576 {
3577 /* We have situation like this:
3578
3579 static Lisp_Symbol *foo;
3580 ...
3581 foo = XSYMBOL(Qt);
3582 ...
3583 pdumper_remember_lv_ptr_raw (&foo, Lisp_Symbol);
3584
3585 Built-in symbols like Qt aren't in the dump!
3586 They're actually in Emacs proper. We need a
3587 special case to point this value back at Emacs
3588 instead of to something in the dump that
3589 isn't there.
3590
3591 An analogous situation applies to subrs, since
3592 Lisp_Subr structures always live in Emacs, not
3593 the dump.
3594 */
3595 dump_emacs_reloc_to_emacs_ptr_raw (
3596 ctx, mem, dump_object_emacs_ptr (lv));
3597 }
3598 else
3599 {
3600 eassert (!dump_object_self_representing_p (lv));
3601 dump_off dump_offset = dump_recall_object (ctx, lv);
3602 if (dump_offset <= 0)
3603 error ("raw-pointer object not dumped?!");
3604 dump_emacs_reloc_to_dump_ptr_raw (ctx, mem, dump_offset);
3605 }
3606 }
3607 }
3608 }
3609}
3610
3611static void
3612dump_unwind_cleanup (void *data)
3613{
3614 struct dump_context *ctx = data;
3615 if (ctx->fd >= 0)
3616 emacs_close (ctx->fd);
3617#ifdef REL_ALLOC
3618 if (ctx->blocked_ralloc)
3619 r_alloc_inhibit_buffer_relocation (0);
3620#endif
3621 Vpurify_flag = ctx->old_purify_flag;
3622}
3623
3624/* Return DUMP_OFFSET, making sure it is within the heap. */
3625static dump_off
3626dump_check_dump_off (struct dump_context *ctx, dump_off dump_offset)
3627{
3628 eassert (dump_offset > 0);
3629 if (ctx)
3630 eassert (dump_offset < ctx->end_heap);
3631 return dump_offset;
3632}
3633
3634static void
3635dump_check_emacs_off (dump_off emacs_off)
3636{
3637 eassert (labs (emacs_off) <= 60*1024*1024);
3638}
3639
3640static struct dump_reloc
3641dump_decode_dump_reloc (Lisp_Object lreloc)
3642{
3643 struct dump_reloc reloc;
3644 dump_reloc_set_type (
3645 &reloc,
3646 (enum dump_reloc_type) XFIXNUM (dump_pop (&lreloc)));
3647 eassert (reloc.type <= RELOC_DUMP_TO_EMACS_LV + Lisp_Float);
3648 dump_reloc_set_offset (&reloc, dump_off_from_lisp (dump_pop (&lreloc)));
3649 eassert (NILP (lreloc));
3650 return reloc;
3651}
3652
3653static void
3654dump_emit_dump_reloc (struct dump_context *ctx, Lisp_Object lreloc)
3655{
3656 eassert (ctx->flags.pack_objects);
3657 struct dump_reloc reloc;
3658 dump_object_start (ctx, &reloc, sizeof (reloc));
3659 reloc = dump_decode_dump_reloc (lreloc);
3660 dump_check_dump_off (ctx, dump_reloc_get_offset (reloc));
3661 dump_object_finish (ctx, &reloc, sizeof (reloc));
3662 if (dump_reloc_get_offset (reloc) < ctx->header.discardable_start)
3663 ctx->number_hot_relocations += 1;
3664 else
3665 ctx->number_discardable_relocations += 1;
3666}
3667
3668#ifdef ENABLE_CHECKING
3669static Lisp_Object
3670dump_check_overlap_dump_reloc (Lisp_Object lreloc_a,
3671 Lisp_Object lreloc_b)
3672{
3673 struct dump_reloc reloc_a = dump_decode_dump_reloc (lreloc_a);
3674 struct dump_reloc reloc_b = dump_decode_dump_reloc (lreloc_b);
3675 eassert (dump_reloc_get_offset (reloc_a) <
3676 dump_reloc_get_offset (reloc_b));
3677 return Qnil;
3678}
3679#endif
3680
3681/* Translate a Lisp Emacs-relocation descriptor (a list whose first
3682 element is one of the EMACS_RELOC_* values, encoded as a fixnum)
3683 into an emacs_reloc structure value suitable for writing to the
3684 dump file.
3685*/
3686static struct emacs_reloc
3687decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
3688{
3689 struct emacs_reloc reloc;
3690 memset (&reloc, 0, sizeof (reloc));
3691 ALLOW_IMPLICIT_CONVERSION;
3692 int type = XFIXNUM (dump_pop (&lreloc));
3693 DISALLOW_IMPLICIT_CONVERSION;
3694 reloc.emacs_offset = dump_off_from_lisp (dump_pop (&lreloc));
3695 dump_check_emacs_off (reloc.emacs_offset);
3696 switch (type)
3697 {
3698 case RELOC_EMACS_COPY_FROM_DUMP:
3699 {
3700 emacs_reloc_set_type (&reloc, type);
3701 reloc.u.dump_offset = dump_off_from_lisp (dump_pop (&lreloc));
3702 dump_check_dump_off (ctx, reloc.u.dump_offset);
3703 dump_off length = dump_off_from_lisp (dump_pop (&lreloc));
3704 ALLOW_IMPLICIT_CONVERSION;
3705 reloc.length = length;
3706 DISALLOW_IMPLICIT_CONVERSION;
3707 if (reloc.length != length)
3708 error ("relocation copy length too large");
3709 }
3710 break;
3711 case RELOC_EMACS_IMMEDIATE:
3712 {
3713 emacs_reloc_set_type (&reloc, type);
3714 intmax_t value = intmax_t_from_lisp (dump_pop (&lreloc));
3715 dump_off size = dump_off_from_lisp (dump_pop (&lreloc));
3716 reloc.u.immediate = value;
3717 ALLOW_IMPLICIT_CONVERSION;
3718 reloc.length = size;
3719 DISALLOW_IMPLICIT_CONVERSION;
3720 eassert (reloc.length == size);
3721 }
3722 break;
3723 case RELOC_EMACS_EMACS_PTR_RAW:
3724 emacs_reloc_set_type (&reloc, type);
3725 reloc.u.emacs_offset2 = dump_off_from_lisp (dump_pop (&lreloc));
3726 dump_check_emacs_off (reloc.u.emacs_offset2);
3727 break;
3728 case RELOC_EMACS_DUMP_PTR_RAW:
3729 emacs_reloc_set_type (&reloc, type);
3730 reloc.u.dump_offset = dump_off_from_lisp (dump_pop (&lreloc));
3731 dump_check_dump_off (ctx, reloc.u.dump_offset);
3732 break;
3733 case RELOC_EMACS_DUMP_LV:
3734 case RELOC_EMACS_EMACS_LV:
3735 {
3736 emacs_reloc_set_type (&reloc, type);
3737 Lisp_Object target_value = dump_pop (&lreloc);
3738 /* If the object is self-representing,
3739 dump_emacs_reloc_to_lv didn't do its job.
3740 dump_emacs_reloc_to_lv should have added a
3741 RELOC_EMACS_IMMEDIATE relocation instead. */
3742 eassert (!dump_object_self_representing_p (target_value));
3743 int tag_type = XTYPE (target_value);
3744 ALLOW_IMPLICIT_CONVERSION;
3745 reloc.length = tag_type;
3746 DISALLOW_IMPLICIT_CONVERSION;
3747 eassert (reloc.length == tag_type);
3748
3749 if (type == RELOC_EMACS_EMACS_LV)
3750 {
3751 void *obj_in_emacs = dump_object_emacs_ptr (target_value);
3752 eassert (obj_in_emacs);
3753 reloc.u.emacs_offset2 = emacs_offset (obj_in_emacs);
3754 }
3755 else
3756 {
3757 eassert (!dump_object_emacs_ptr (target_value));
3758 reloc.u.dump_offset = dump_recall_object (ctx, target_value);
3759 if (reloc.u.dump_offset <= 0)
3760 {
3761 Lisp_Object repr = Fprin1_to_string (target_value, Qnil);
3762 error ("relocation target was not dumped: %s", SDATA (repr));
3763 }
3764 dump_check_dump_off (ctx, reloc.u.dump_offset);
3765 }
3766 }
3767 break;
3768 default:
3769 eassume (!"not reached");
3770 }
3771
3772 /* We should have consumed the whole relocation descriptor. */
3773 eassert (NILP (lreloc));
3774
3775 return reloc;
3776}
3777
3778static void
3779dump_emit_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
3780{
3781 eassert (ctx->flags.pack_objects);
3782 struct emacs_reloc reloc;
3783 dump_object_start (ctx, &reloc, sizeof (reloc));
3784 reloc = decode_emacs_reloc (ctx, lreloc);
3785 dump_object_finish (ctx, &reloc, sizeof (reloc));
3786}
3787
3788static Lisp_Object
3789dump_merge_emacs_relocs (Lisp_Object lreloc_a, Lisp_Object lreloc_b)
3790{
3791 /* Combine copy relocations together if they're copying from
3792 adjacent chunks to adjacent chunks. */
3793
3794#ifdef ENABLE_CHECKING
3795 {
3796 dump_off off_a = dump_off_from_lisp (XCAR (XCDR (lreloc_a)));
3797 dump_off off_b = dump_off_from_lisp (XCAR (XCDR (lreloc_b)));
3798 eassert (off_a <= off_b); /* Catch sort errors. */
3799 eassert (off_a < off_b); /* Catch duplicate relocations. */
3800 }
3801#endif
3802
3803 if (XFIXNUM (XCAR (lreloc_a)) != RELOC_EMACS_COPY_FROM_DUMP ||
3804 XFIXNUM (XCAR (lreloc_b)) != RELOC_EMACS_COPY_FROM_DUMP)
3805 return Qnil;
3806
3807 struct emacs_reloc reloc_a = decode_emacs_reloc (NULL, lreloc_a);
3808 struct emacs_reloc reloc_b = decode_emacs_reloc (NULL, lreloc_b);
3809
3810 eassert (reloc_a.type == RELOC_EMACS_COPY_FROM_DUMP);
3811 eassert (reloc_b.type == RELOC_EMACS_COPY_FROM_DUMP);
3812
3813 if (reloc_a.emacs_offset + reloc_a.length != reloc_b.emacs_offset)
3814 return Qnil;
3815
3816 if (reloc_a.u.dump_offset + reloc_a.length != reloc_b.u.dump_offset)
3817 return Qnil;
3818
3819 dump_off new_length = reloc_a.length + reloc_b.length;
3820 ALLOW_IMPLICIT_CONVERSION;
3821 reloc_a.length = new_length;
3822 DISALLOW_IMPLICIT_CONVERSION;
3823 if (reloc_a.length != new_length)
3824 return Qnil; /* Overflow */
3825
3826 return list4 (make_fixnum (RELOC_EMACS_COPY_FROM_DUMP),
3827 dump_off_to_lisp (reloc_a.emacs_offset),
3828 dump_off_to_lisp (reloc_a.u.dump_offset),
3829 dump_off_to_lisp (reloc_a.length));
3830}
3831
3832typedef void (*drain_reloc_handler)(struct dump_context *, Lisp_Object);
3833typedef Lisp_Object (*drain_reloc_merger)(Lisp_Object a, Lisp_Object b);
3834
3835static void
3836drain_reloc_list (struct dump_context *ctx,
3837 drain_reloc_handler handler,
3838 drain_reloc_merger merger,
3839 Lisp_Object *reloc_list,
3840 struct dump_table_locator *out_locator)
3841{
3842 struct dump_flags old_flags = ctx->flags;
3843 ctx->flags.pack_objects = true;
3844 Lisp_Object relocs = Fsort (Fnreverse (*reloc_list),
3845 Qdump_emacs_portable__sort_predicate);
3846 *reloc_list = Qnil;
3847 dump_align_output (ctx, sizeof (dump_off));
3848 struct dump_table_locator locator;
3849 memset (&locator, 0, sizeof (locator));
3850 locator.offset = ctx->offset;
3851 for (; !NILP (relocs); locator.nr_entries += 1)
3852 {
3853 Lisp_Object reloc = dump_pop (&relocs);
3854 Lisp_Object merged;
3855 while (merger != NULL &&
3856 !NILP (relocs) &&
3857 ((merged = merger (reloc, XCAR (relocs))), !NILP (merged)))
3858 {
3859 reloc = merged;
3860 relocs = XCDR (relocs);
3861 }
3862 handler (ctx, reloc);
3863 }
3864 *out_locator = locator;
3865 ctx->flags = old_flags;
3866}
3867
3868static void
3869dump_do_fixup (struct dump_context *ctx,
3870 Lisp_Object fixup,
3871 Lisp_Object prev_fixup)
3872{
3873 enum dump_fixup_type type =
3874 (enum dump_fixup_type) XFIXNUM (dump_pop (&fixup));
3875 dump_off dump_fixup_offset = dump_off_from_lisp (dump_pop (&fixup));
3876#ifdef ENABLE_CHECKING
3877 if (!NILP (prev_fixup))
3878 {
3879 dump_off prev_dump_fixup_offset =
3880 dump_off_from_lisp (XCAR (XCDR (prev_fixup)));
3881 eassert (dump_fixup_offset - prev_dump_fixup_offset
3882 >= sizeof (void*));
3883 }
3884#endif
3885 Lisp_Object arg = dump_pop (&fixup);
3886 eassert (NILP (fixup));
3887 dump_seek (ctx, dump_fixup_offset);
3888 intptr_t dump_value;
3889 bool do_write = true;
3890 switch (type)
3891 {
3892 case DUMP_FIXUP_LISP_OBJECT:
3893 case DUMP_FIXUP_LISP_OBJECT_RAW:
3894 /* Dump wants a pointer to a Lisp object.
3895 If DUMP_FIXUP_LISP_OBJECT_RAW, we should stick a C pointer in
3896 the dump; otherwise, a Lisp_Object. */
3897 if (SUBRP (arg))
3898 {
3899 dump_value = emacs_offset (XSUBR (arg));
3900 if (type == DUMP_FIXUP_LISP_OBJECT)
3901 dump_reloc_dump_to_emacs_lv (ctx, ctx->offset, XTYPE (arg));
3902 else
3903 dump_reloc_dump_to_emacs_ptr_raw (ctx, ctx->offset);
3904 }
3905 else if (dump_builtin_symbol_p (arg))
3906 {
3907 eassert (dump_object_self_representing_p (arg));
3908 /* These symbols are part of Emacs, so point there. If we
3909 want a Lisp_Object, we're set. If we want a raw pointer,
3910 we need to emit a relocation. */
3911 if (type == DUMP_FIXUP_LISP_OBJECT)
3912 {
3913 do_write = false;
3914 dump_write (ctx, &arg, sizeof (arg));
3915 }
3916 else
3917 {
3918 dump_value = emacs_offset (XSYMBOL (arg));
3919 dump_reloc_dump_to_emacs_ptr_raw (ctx, ctx->offset);
3920 }
3921 }
3922 else
3923 {
3924 eassert (dump_object_emacs_ptr (arg) == NULL);
3925 dump_value = dump_recall_object (ctx, arg);
3926 if (dump_value <= 0)
3927 error ("fixup object not dumped");
3928 if (type == DUMP_FIXUP_LISP_OBJECT)
3929 dump_reloc_dump_to_dump_lv (ctx, ctx->offset, XTYPE (arg));
3930 else
3931 dump_reloc_dump_to_dump_ptr_raw (ctx, ctx->offset);
3932 }
3933 break;
3934 case DUMP_FIXUP_PTR_DUMP_RAW:
3935 /* Dump wants a raw pointer to something that's not a lisp
3936 object. It knows the exact location it wants, so just
3937 believe it. */
3938 dump_value = dump_off_from_lisp (arg);
3939 dump_reloc_dump_to_dump_ptr_raw (ctx, ctx->offset);
3940 break;
3941 case DUMP_FIXUP_BIGNUM_DATA:
3942 {
3943 eassert (BIGNUMP (arg));
3944 arg = Fgethash (arg, ctx->bignum_data, Qnil);
3945 if (NILP (arg))
3946 error ("bignum not dumped");
3947 struct bignum_reload_info reload_info = { 0 };
3948 reload_info.data_location = dump_off_from_lisp (dump_pop (&arg));
3949 reload_info.nlimbs = dump_off_from_lisp (dump_pop (&arg));
3950 eassert (NILP (arg));
3951 dump_write (ctx, &reload_info, sizeof (reload_info));
3952 do_write = false;
3953 break;
3954 }
3955 default:
3956 emacs_abort ();
3957 }
3958 if (do_write)
3959 dump_write (ctx, &dump_value, sizeof (dump_value));
3960}
3961
3962static void
3963dump_do_fixups (struct dump_context *ctx)
3964{
3965 dump_off saved_offset = ctx->offset;
3966 Lisp_Object fixups = Fsort (Fnreverse (ctx->fixups),
3967 Qdump_emacs_portable__sort_predicate);
3968 Lisp_Object prev_fixup = Qnil;
3969 ctx->fixups = Qnil;
3970 while (!NILP (fixups))
3971 {
3972 Lisp_Object fixup = dump_pop (&fixups);
3973 dump_do_fixup (ctx, fixup, prev_fixup);
3974 prev_fixup = fixup;
3975 }
3976 dump_seek (ctx, saved_offset);
3977}
3978
3979static void
3980dump_drain_normal_queue (struct dump_context *ctx)
3981{
3982 while (!dump_queue_empty_p (&ctx->dump_queue))
3983 dump_object (ctx, dump_queue_dequeue (&ctx->dump_queue, ctx->offset));
3984}
3985
3986static void
3987dump_drain_deferred_hash_tables (struct dump_context *ctx)
3988{
3989 struct dump_flags old_flags = ctx->flags;
3990
3991 /* Now we want to actually write the hash tables. */
3992 ctx->flags.defer_hash_tables = false;
3993
3994 Lisp_Object deferred_hash_tables = Fnreverse (ctx->deferred_hash_tables);
3995 ctx->deferred_hash_tables = Qnil;
3996 while (!NILP (deferred_hash_tables))
3997 dump_object (ctx, dump_pop (&deferred_hash_tables));
3998 ctx->flags = old_flags;
3999}
4000
4001static void
4002dump_drain_deferred_symbols (struct dump_context *ctx)
4003{
4004 struct dump_flags old_flags = ctx->flags;
4005
4006 /* Now we want to actually write the symbols. */
4007 ctx->flags.defer_symbols = false;
4008
4009 Lisp_Object deferred_symbols = Fnreverse (ctx->deferred_symbols);
4010 ctx->deferred_symbols = Qnil;
4011 while (!NILP (deferred_symbols))
4012 dump_object (ctx, dump_pop (&deferred_symbols));
4013 ctx->flags = old_flags;
4014}
4015
4016DEFUN ("dump-emacs-portable",
4017 Fdump_emacs_portable, Sdump_emacs_portable,
4018 1, 2, 0,
4019 doc: /* Dump current state of Emacs into dump file FILENAME.
4020If TRACK-REFERRERS is non-nil, keep additional debugging information
4021that can help track down the provenance of unsupported object
4022types. */)
4023 (Lisp_Object filename, Lisp_Object track_referrers)
4024{
4025 eassert (initialized);
4026
4027 if (will_dump_with_unexec_p ())
4028 error ("This Emacs instance was started under the assumption "
4029 "that it would be dumped with unexec, not the portable "
4030 "dumper. Dumping with the portable dumper may produce "
4031 "unexpected results.");
4032
4033 if (!main_thread_p (current_thread))
4034 error ("Function can be called only on main thread");
4035
4036 if (!NILP (XCDR (Fall_threads ())))
4037 error ("No other threads can be running");
4038
4039 /* Clear out any detritus in memory. */
4040 do {
4041 number_finalizers_run = 0;
4042 Fgarbage_collect ();
4043 } while (number_finalizers_run);
4044
4045 ptrdiff_t count = SPECPDL_INDEX ();
4046
4047 /* Bind `command-line-processed' to nil before dumping,
4048 so that the dumped Emacs will process its command line
4049 and set up to work with X windows if appropriate. */
4050 Lisp_Object symbol = intern ("command-line-processed");
4051 specbind (symbol, Qnil);
4052
4053 CHECK_STRING (filename);
4054 filename = Fexpand_file_name (filename, Qnil);
4055 filename = ENCODE_FILE (filename);
4056
4057 struct dump_context ctx_buf;
4058 struct dump_context *ctx = &ctx_buf;
4059 memset (ctx, 0, sizeof (*ctx));
4060 ctx->fd = -1;
4061
4062 ctx->objects_dumped = make_eq_hash_table ();
4063 dump_queue_init (&ctx->dump_queue);
4064 ctx->deferred_hash_tables = Qnil;
4065 ctx->deferred_symbols = Qnil;
4066
4067 ctx->fixups = Qnil;
4068 ctx->staticpro_table = CALLN (Fmake_hash_table);
4069 ctx->symbol_aux = Qnil;
4070 ctx->copied_queue = Qnil;
4071 ctx->cold_queue = Qnil;
4072 ctx->dump_relocs = Qnil;
4073 ctx->object_starts = Qnil;
4074 ctx->emacs_relocs = Qnil;
4075 ctx->bignum_data = make_eq_hash_table ();
4076
4077 /* Ordinarily, dump_object should remember where it saw objects and
4078 actually write the object contents to the dump file. In special
4079 circumstances below, we temporarily change this default
4080 behavior. */
4081 ctx->flags.dump_object_contents = true;
4082 ctx->flags.record_object_starts = true;
4083
4084 /* We want to consolidate certain object types that we know are very likely
4085 to be modified. */
4086 ctx->flags.defer_hash_tables = true;
4087 // ctx->flags.defer_symbols = true; XXX
4088
4089 /* These objects go into special sections. */
4090 ctx->flags.defer_cold_objects = true;
4091 ctx->flags.defer_copied_objects = true;
4092
4093 ctx->current_referrer = Qnil;
4094 if (!NILP (track_referrers))
4095 ctx->referrers = make_eq_hash_table ();
4096
4097 ctx->dump_filename = filename;
4098
4099 record_unwind_protect_ptr (dump_unwind_cleanup, ctx);
4100 block_input ();
4101
4102#ifdef REL_ALLOC
4103 r_alloc_inhibit_buffer_relocation (1);
4104 ctx->blocked_ralloc = true;
4105#endif
4106
4107 ctx->old_purify_flag = Vpurify_flag;
4108 Vpurify_flag = Qnil;
4109
4110 /* Make sure various weird things are less likely to happen. */
4111 ctx->old_post_gc_hook = Vpost_gc_hook;
4112 Vpost_gc_hook = Qnil;
4113
4114 ctx->fd = emacs_open (SSDATA (filename),
4115 O_RDWR | O_TRUNC | O_CREAT, 0666);
4116 if (ctx->fd < 0)
4117 report_file_error ("Opening dump output", filename);
4118 verify (sizeof (ctx->header.magic) == sizeof (dump_magic));
4119 memcpy (&ctx->header.magic, dump_magic, sizeof (dump_magic));
4120 ctx->header.magic[0] = '!'; /* Note that dump is incomplete. */
4121
4122 verify (sizeof (fingerprint) == sizeof (ctx->header.fingerprint));
4123 memcpy (ctx->header.fingerprint, fingerprint, sizeof (fingerprint));
4124
4125 const dump_off header_start = ctx->offset;
4126 dump_fingerprint ("dumping fingerprint", ctx->header.fingerprint);
4127 dump_write (ctx, &ctx->header, sizeof (ctx->header));
4128 const dump_off header_end = ctx->offset;
4129
4130 const dump_off hot_start = ctx->offset;
4131 /* Start the dump process by processing the static roots and
4132 queuing up the objects to which they refer. */
4133 dump_roots (ctx);
4134
4135 dump_charset_table (ctx);
4136 dump_finalizer_list_head_ptr (ctx, &finalizers.prev);
4137 dump_finalizer_list_head_ptr (ctx, &finalizers.next);
4138 dump_finalizer_list_head_ptr (ctx, &doomed_finalizers.prev);
4139 dump_finalizer_list_head_ptr (ctx, &doomed_finalizers.next);
4140 dump_drain_user_remembered_data_hot (ctx);
4141
4142 /* We've already remembered all the objects to which GC roots point,
4143 but we have to manually save the list of GC roots itself. */
4144 dump_metadata_for_pdumper (ctx);
4145 for (int i = 0; i < staticidx; ++i)
4146 dump_emacs_reloc_to_emacs_ptr_raw (ctx, &staticvec[i], staticvec[i]);
4147 dump_emacs_reloc_immediate_int (ctx, &staticidx, staticidx);
4148
4149 /* Dump until while we keep finding objects to dump. We add new
4150 objects to the queue by side effect during dumping.
4151 We accumulate some types of objects in special lists to get more
4152 locality for these object types at runtime. */
4153 do {
4154 dump_drain_deferred_hash_tables (ctx);
4155 dump_drain_deferred_symbols (ctx);
4156 dump_drain_normal_queue (ctx);
4157 } while (!dump_queue_empty_p (&ctx->dump_queue) ||
4158 !NILP (ctx->deferred_hash_tables) ||
4159 !NILP (ctx->deferred_symbols));
4160
4161 dump_sort_copied_objects (ctx);
4162
4163 /* While we copy built-in symbols into the Emacs image, these
4164 built-in structures refer to non-Lisp heap objects that must live
4165 in the dump; we stick these auxiliary data structures at the end
4166 of the hot section and use a special hash table to remember them.
4167 The actual symbol dump will pick them up below. */
4168 ctx->symbol_aux = make_eq_hash_table ();
4169 dump_hot_parts_of_discardable_objects (ctx);
4170
4171 /* Emacs, after initial dump loading, can forget about the portion
4172 of the dump that runs from here to the start of the cold section.
4173 This section consists of objects that need to be memcpy()ed into
4174 the Emacs data section instead of just used directly.
4175
4176 We don't need to align hot_end: the loader knows to actually
4177 start discarding only at the next page boundary if the loader
4178 implements discarding using page manipulation. */
4179 const dump_off hot_end = ctx->offset;
4180 ctx->header.discardable_start = hot_end;
4181
4182 dump_drain_copied_objects (ctx);
4183 eassert (dump_queue_empty_p (&ctx->dump_queue));
4184
4185 dump_off discardable_end = ctx->offset;
4186 dump_align_output (ctx, dump_get_page_size ());
4187 ctx->header.cold_start = ctx->offset;
4188
4189 /* Start the cold section. This section contains bytes that should
4190 never change and so can be direct-mapped from the dump without
4191 special processing. */
4192 dump_drain_cold_data (ctx);
4193 /* dump_drain_user_remembered_data_cold needs to be after
4194 dump_drain_cold_data in case dump_drain_cold_data dumps a lisp
4195 object to which C code points.
4196 dump_drain_user_remembered_data_cold assumes that all lisp
4197 objects have been dumped. */
4198 dump_drain_user_remembered_data_cold (ctx);
4199
4200 /* After this point, the dump file contains no data that can be part
4201 of the Lisp heap. */
4202 ctx->end_heap = ctx->offset;
4203
4204 /* Make remembered modifications to the dump file itself. */
4205 dump_do_fixups (ctx);
4206
4207 drain_reloc_merger emacs_reloc_merger =
4208#ifdef ENABLE_CHECKING
4209 dump_check_overlap_dump_reloc
4210#else
4211 NULL
4212#endif
4213 ;
4214
4215 /* Emit instructions for Emacs to execute when loading the dump.
4216 Note that this relocation information ends up in the cold section
4217 of the dump. */
4218 drain_reloc_list (
4219 ctx,
4220 dump_emit_dump_reloc,
4221 emacs_reloc_merger,
4222 &ctx->dump_relocs,
4223 &ctx->header.dump_relocs);
4224 unsigned number_hot_relocations = ctx->number_hot_relocations;
4225 ctx->number_hot_relocations = 0;
4226 unsigned number_discardable_relocations = ctx->number_discardable_relocations;
4227 ctx->number_discardable_relocations = 0;
4228 drain_reloc_list (
4229 ctx,
4230 dump_emit_dump_reloc,
4231 emacs_reloc_merger,
4232 &ctx->object_starts,
4233 &ctx->header.object_starts);
4234 drain_reloc_list (
4235 ctx, dump_emit_emacs_reloc,
4236 dump_merge_emacs_relocs,
4237 &ctx->emacs_relocs,
4238 &ctx->header.emacs_relocs);
4239
4240 const dump_off cold_end = ctx->offset;
4241
4242 eassert (dump_queue_empty_p (&ctx->dump_queue));
4243 eassert (NILP (ctx->copied_queue));
4244 eassert (NILP (ctx->cold_queue));
4245 eassert (NILP (ctx->deferred_symbols));
4246 eassert (NILP (ctx->deferred_hash_tables));
4247 eassert (NILP (ctx->fixups));
4248 eassert (NILP (ctx->dump_relocs));
4249 eassert (NILP (ctx->emacs_relocs));
4250
4251 /* Dump is complete. Go back to the header and write the magic
4252 indicating that the dump is complete and can be loaded. */
4253 ctx->header.magic[0] = dump_magic[0];
4254 dump_seek (ctx, 0);
4255 dump_write (ctx, &ctx->header, sizeof (ctx->header));
4256
4257 fprintf (stderr, "Dump complete\n");
4258 fprintf (stderr,
4259 "Byte counts: header=%lu hot=%lu discardable=%lu cold=%lu\n",
4260 (unsigned long) (header_end - header_start),
4261 (unsigned long) (hot_end - hot_start),
4262 (unsigned long) (discardable_end - ctx->header.discardable_start),
4263 (unsigned long) (cold_end - ctx->header.cold_start));
4264 fprintf (stderr, "Reloc counts: hot=%u discardable=%u\n",
4265 number_hot_relocations,
4266 number_discardable_relocations);
4267
4268 unblock_input ();
4269 return unbind_to (count, Qnil);
4270}
4271
4272DEFUN ("dump-emacs-portable--sort-predicate",
4273 Fdump_emacs_portable__sort_predicate,
4274 Sdump_emacs_portable__sort_predicate,
4275 2, 2, 0,
4276 doc: /* Internal relocation sorting function. */)
4277 (Lisp_Object a, Lisp_Object b)
4278{
4279 dump_off a_offset = dump_off_from_lisp (XCAR (XCDR (a)));
4280 dump_off b_offset = dump_off_from_lisp (XCAR (XCDR (b)));
4281 return a_offset < b_offset ? Qt : Qnil;
4282}
4283
4284DEFUN ("dump-emacs-portable--sort-predicate-copied",
4285 Fdump_emacs_portable__sort_predicate_copied,
4286 Sdump_emacs_portable__sort_predicate_copied,
4287 2, 2, 0,
4288 doc: /* Internal relocation sorting function. */)
4289 (Lisp_Object a, Lisp_Object b)
4290{
4291 eassert (dump_object_emacs_ptr (a));
4292 eassert (dump_object_emacs_ptr (b));
4293 return dump_object_emacs_ptr (a) < dump_object_emacs_ptr (b) ? Qt : Qnil;
4294}
4295
4296void
4297pdumper_do_now_and_after_load_impl (pdumper_hook hook)
4298{
4299 if (nr_dump_hooks == ARRAYELTS (dump_hooks))
4300 fatal ("out of dump hooks: make dump_hooks[] bigger");
4301 dump_hooks[nr_dump_hooks++] = hook;
4302 hook ();
4303}
4304
4305static void
4306pdumper_remember_user_data_1 (void *mem, int nbytes)
4307{
4308 if (nr_remembered_data == ARRAYELTS (remembered_data))
4309 fatal ("out of remembered data slots: make remembered_data[] bigger");
4310 remembered_data[nr_remembered_data].mem = mem;
4311 remembered_data[nr_remembered_data].sz = nbytes;
4312 nr_remembered_data += 1;
4313}
4314
4315void
4316pdumper_remember_scalar_impl (void *mem, ptrdiff_t nbytes)
4317{
4318 eassert (0 <= nbytes && nbytes <= INT_MAX);
4319 if (nbytes > 0)
4320 pdumper_remember_user_data_1 (mem, (int) nbytes);
4321}
4322
4323void
4324pdumper_remember_lv_ptr_raw_impl (void* ptr, enum Lisp_Type type)
4325{
4326 pdumper_remember_user_data_1 (ptr, -type);
4327}
4328
4329
4330/* Dump runtime */
4331enum dump_memory_protection {
4332 DUMP_MEMORY_ACCESS_NONE = 1,
4333 DUMP_MEMORY_ACCESS_READ = 2,
4334 DUMP_MEMORY_ACCESS_READWRITE = 3,
4335};
4336
4337static void *
4338dump_anonymous_allocate_w32 (void *base,
4339 size_t size,
4340 enum dump_memory_protection protection)
4341{
4342#if VM_SUPPORTED != VM_MS_WINDOWS
4343 (void) base;
4344 (void) size;
4345 (void) protection;
4346 emacs_abort ();
4347#else
4348 void *ret;
4349 DWORD mem_type;
4350 DWORD mem_prot;
4351
4352 switch (protection)
4353 {
4354 case DUMP_MEMORY_ACCESS_NONE:
4355 mem_type = MEM_RESERVE;
4356 mem_prot = PAGE_NOACCESS;
4357 break;
4358 case DUMP_MEMORY_ACCESS_READ:
4359 mem_type = MEM_COMMIT;
4360 mem_prot = PAGE_READONLY;
4361 break;
4362 case DUMP_MEMORY_ACCESS_READWRITE:
4363 mem_type = MEM_COMMIT;
4364 mem_prot = PAGE_READWRITE;
4365 break;
4366 default:
4367 emacs_abort ();
4368 }
4369
4370 ret = VirtualAlloc (base, size, mem_type, mem_prot);
4371 if (ret == NULL)
4372 errno = (base && GetLastError () == ERROR_INVALID_ADDRESS)
4373 ? EBUSY
4374 : EPERM;
4375 return ret;
4376#endif
4377}
4378
4379/* Old versions of macOS only define MAP_ANON, not MAP_ANONYMOUS.
4380 FIXME: This probably belongs elsewhere (gnulib/autoconf?) */
4381#ifndef MAP_ANONYMOUS
4382#define MAP_ANONYMOUS MAP_ANON
4383#endif
4384
4385static void *
4386dump_anonymous_allocate_posix (void *base,
4387 size_t size,
4388 enum dump_memory_protection protection)
4389{
4390#if VM_SUPPORTED != VM_POSIX
4391 (void) base;
4392 (void) size;
4393 (void) protection;
4394 emacs_abort ();
4395#else
4396 void *ret;
4397 int mem_prot;
4398
4399 switch (protection)
4400 {
4401 case DUMP_MEMORY_ACCESS_NONE:
4402 mem_prot = PROT_NONE;
4403 break;
4404 case DUMP_MEMORY_ACCESS_READ:
4405 mem_prot = PROT_READ;
4406 break;
4407 case DUMP_MEMORY_ACCESS_READWRITE:
4408 mem_prot = PROT_READ | PROT_WRITE;
4409 break;
4410 default:
4411 emacs_abort ();
4412 }
4413
4414 int mem_flags = MAP_PRIVATE | MAP_ANONYMOUS;
4415 if (mem_prot != PROT_NONE)
4416 mem_flags |= MAP_POPULATE;
4417 if (base)
4418 mem_flags |= MAP_FIXED;
4419
4420 bool retry;
4421 do
4422 {
4423 retry = false;
4424 ret = mmap (base, size, mem_prot, mem_flags, -1, 0);
4425 if (ret == MAP_FAILED &&
4426 errno == EINVAL &&
4427 (mem_flags & MAP_POPULATE))
4428 {
4429 /* This system didn't understand MAP_POPULATE, so try
4430 again without it. */
4431 mem_flags &= ~MAP_POPULATE;
4432 retry = true;
4433 }
4434 }
4435 while (retry);
4436
4437 if (ret == MAP_FAILED)
4438 ret = NULL;
4439 return ret;
4440#endif
4441}
4442
4443/* Perform anonymous memory allocation. */
4444static void *
4445dump_anonymous_allocate (void *base,
4446 const size_t size,
4447 enum dump_memory_protection protection)
4448{
4449 void *ret = NULL;
4450 if (VM_SUPPORTED == VM_MS_WINDOWS)
4451 ret = dump_anonymous_allocate_w32 (base, size, protection);
4452 else if (VM_SUPPORTED == VM_POSIX)
4453 ret = dump_anonymous_allocate_posix (base, size, protection);
4454 else
4455 errno = ENOSYS;
4456 return ret;
4457}
4458
4459/* Undo the effect of dump_reserve_address_space(). */
4460static void
4461dump_anonymous_release (void *addr, size_t size)
4462{
4463 eassert (size >= 0);
4464#if VM_SUPPORTED == VM_MS_WINDOWS
4465 (void) size;
4466 if (!VirtualFree (addr, 0, MEM_RELEASE))
4467 emacs_abort ();
4468#elif VM_SUPPORTED == VM_POSIX
4469 if (munmap (addr, size) < 0)
4470 emacs_abort ();
4471#else
4472 (void) addr;
4473 (void) size;
4474 emacs_abort ();
4475#endif
4476}
4477
4478static void *
4479dump_map_file_w32 (
4480 void *base,
4481 int fd,
4482 off_t offset,
4483 size_t size,
4484 enum dump_memory_protection protection)
4485{
4486#if VM_SUPPORTED != VM_MS_WINDOWS
4487 (void) base;
4488 (void) fd;
4489 (void) offset;
4490 (void) size;
4491 (void) protection;
4492 emacs_abort ();
4493#else
4494 void *ret = NULL;
4495 HANDLE section = NULL;
4496 HANDLE file;
4497
4498 uint64_t full_offset = offset;
4499 uint32_t offset_high = (uint32_t) (full_offset >> 32);
4500 uint32_t offset_low = (uint32_t) (full_offset & 0xffffffff);
4501
4502 int error;
4503 DWORD map_access;
4504
4505 file = (HANDLE) _get_osfhandle (fd);
4506 if (file == INVALID_HANDLE_VALUE)
4507 goto out;
4508
4509 section = CreateFileMapping (
4510 file,
4511 /*lpAttributes=*/NULL,
4512 PAGE_READONLY,
4513 /*dwMaximumSizeHigh=*/0,
4514 /*dwMaximumSizeLow=*/0,
4515 /*lpName=*/NULL);
4516 if (!section)
4517 {
4518 errno = EINVAL;
4519 goto out;
4520 }
4521
4522 switch (protection)
4523 {
4524 case DUMP_MEMORY_ACCESS_NONE:
4525 case DUMP_MEMORY_ACCESS_READ:
4526 map_access = FILE_MAP_READ;
4527 break;
4528 case DUMP_MEMORY_ACCESS_READWRITE:
4529 map_access = FILE_MAP_COPY;
4530 break;
4531 default:
4532 emacs_abort ();
4533 }
4534
4535 ret = MapViewOfFileEx (section,
4536 map_access,
4537 offset_high,
4538 offset_low,
4539 size,
4540 base);
4541
4542 error = GetLastError ();
4543 if (ret == NULL)
4544 errno = (error == ERROR_INVALID_ADDRESS ? EBUSY : EPERM);
4545 out:
4546 if (section && !CloseHandle (section))
4547 emacs_abort ();
4548 return ret;
4549#endif
4550}
4551
4552static void *
4553dump_map_file_posix (
4554 void *base,
4555 int fd,
4556 off_t offset,
4557 size_t size,
4558 enum dump_memory_protection protection)
4559{
4560#if VM_SUPPORTED != VM_POSIX
4561 (void) base;
4562 (void) fd;
4563 (void) offset;
4564 (void) size;
4565 (void) protection;
4566 emacs_abort ();
4567#else
4568 void *ret;
4569 int mem_prot;
4570 int mem_flags;
4571
4572 switch (protection)
4573 {
4574 case DUMP_MEMORY_ACCESS_NONE:
4575 mem_prot = PROT_NONE;
4576 mem_flags = MAP_SHARED;
4577 break;
4578 case DUMP_MEMORY_ACCESS_READ:
4579 mem_prot = PROT_READ;
4580 mem_flags = MAP_SHARED;
4581 break;
4582 case DUMP_MEMORY_ACCESS_READWRITE:
4583 mem_prot = PROT_READ | PROT_WRITE;
4584 mem_flags = MAP_PRIVATE;
4585 break;
4586 default:
4587 emacs_abort ();
4588 }
4589
4590 if (base)
4591 mem_flags |= MAP_FIXED;
4592
4593 ret = mmap (base, size, mem_prot, mem_flags, fd, offset);
4594 if (ret == MAP_FAILED)
4595 ret = NULL;
4596 return ret;
4597#endif
4598}
4599
4600/* Map a file into memory. */
4601static void *
4602dump_map_file (
4603 void *base,
4604 int fd,
4605 off_t offset,
4606 size_t size,
4607 enum dump_memory_protection protection)
4608{
4609 void *ret = NULL;
4610 if (VM_SUPPORTED == VM_MS_WINDOWS)
4611 ret = dump_map_file_w32 (base, fd, offset, size, protection);
4612 else if (VM_SUPPORTED == VM_POSIX)
4613 ret = dump_map_file_posix (base, fd, offset, size, protection);
4614 else
4615 errno = ENOSYS;
4616 return ret;
4617}
4618
4619/* Remove a virtual memory mapping.
4620
4621 On failure, abort Emacs. For maximum platform compatibility, ADDR
4622 and SIZE must match the mapping exactly. */
4623static void
4624dump_unmap_file (void *addr, size_t size)
4625{
4626 eassert (size >= 0);
4627#if !VM_SUPPORTED
4628 (void) addr;
4629 (void) size;
4630 emacs_abort ();
4631#elif defined (WINDOWSNT)
4632 (void) size;
4633 if (!UnmapViewOfFile (addr))
4634 emacs_abort ();
4635#else
4636 if (munmap (addr, size) < 0)
4637 emacs_abort ();
4638#endif
4639}
4640
4641struct dump_memory_map_spec
4642{
4643 int fd; /* File to map; anon zero if negative. */
4644 size_t size; /* Number of bytes to map. */
4645 off_t offset; /* Offset within fd. */
4646 enum dump_memory_protection protection;
4647};
4648
4649struct dump_memory_map {
4650 struct dump_memory_map_spec spec;
4651 void *mapping; /* Actual mapped memory. */
4652 void (*release)(struct dump_memory_map *);
4653 void *private;
4654};
4655
4656/* Mark the pages as unneeded, potentially zeroing them, without
4657 releasing the address space reservation. */
4658static void
4659dump_discard_mem (void *mem, size_t size)
4660{
4661#if VM_SUPPORTED == VM_MS_WINDOWS
4662 /* Discard COWed pages. */
4663 (void) VirtualFree (mem, size, MEM_DECOMMIT);
4664 /* Release the commit charge for the mapping. */
4665 (void) VirtualProtect (mem, size, PAGE_NOACCESS, NULL);
4666#elif VM_SUPPORTED == VM_POSIX
4667# ifdef HAVE_POSIX_MADVISE
4668 /* Discard COWed pages. */
4669 (void) posix_madvise (mem, size, POSIX_MADV_DONTNEED);
4670# endif
4671 /* Release the commit charge for the mapping. */
4672 (void) mprotect (mem, size, PROT_NONE);
4673#endif
4674}
4675
4676static void
4677dump_mmap_discard_contents (struct dump_memory_map *map)
4678{
4679 if (map->mapping)
4680 dump_discard_mem (map->mapping, map->spec.size);
4681}
4682
4683static void
4684dump_mmap_reset (struct dump_memory_map *map)
4685{
4686 map->mapping = NULL;
4687 map->release = NULL;
4688 map->private = NULL;
4689}
4690
4691static void
4692dump_mmap_release (struct dump_memory_map *map)
4693{
4694 if (map->release)
4695 map->release (map);
4696 dump_mmap_reset (map);
4697}
4698
4699/* Allows heap-allocated dump_mmap to "free" maps individually. */
4700struct dump_memory_map_heap_control_block {
4701 int refcount;
4702 void *mem;
4703};
4704
4705static void
4706dump_mm_heap_cb_release (struct dump_memory_map_heap_control_block *cb)
4707{
4708 eassert (cb->refcount > 0);
4709 if (--cb->refcount == 0)
4710 {
4711 free (cb->mem);
4712 free (cb);
4713 }
4714}
4715
4716static void
4717dump_mmap_release_heap (struct dump_memory_map *map)
4718{
4719 struct dump_memory_map_heap_control_block *cb = map->private;
4720 dump_mm_heap_cb_release (cb);
4721}
4722
4723/* Implement dump_mmap using malloc and read. */
4724static bool
4725dump_mmap_contiguous_heap (
4726 struct dump_memory_map *maps,
4727 int nr_maps,
4728 size_t total_size)
4729{
4730 bool ret = false;
4731 struct dump_memory_map_heap_control_block *cb = calloc (1, sizeof (*cb));
4732 char *mem;
4733 if (!cb)
4734 goto out;
4735 cb->refcount = 1;
4736 cb->mem = malloc (total_size);
4737 if (!cb->mem)
4738 goto out;
4739 mem = cb->mem;
4740 for (int i = 0; i < nr_maps; ++i)
4741 {
4742 struct dump_memory_map *map = &maps[i];
4743 const struct dump_memory_map_spec spec = map->spec;
4744 if (!spec.size)
4745 continue;
4746 map->mapping = mem;
4747 mem += spec.size;
4748 map->release = dump_mmap_release_heap;
4749 map->private = cb;
4750 cb->refcount += 1;
4751 if (spec.fd < 0)
4752 memset (map->mapping, 0, spec.size);
4753 else
4754 {
4755 if (lseek (spec.fd, spec.offset, SEEK_SET) < 0)
4756 goto out;
4757 ssize_t nb = dump_read_all (spec.fd,
4758 map->mapping,
4759 spec.size);
4760 if (nb >= 0 && nb != spec.size)
4761 errno = EIO;
4762 if (nb != spec.size)
4763 goto out;
4764 }
4765 }
4766
4767 ret = true;
4768 out:
4769 dump_mm_heap_cb_release (cb);
4770 if (!ret)
4771 for (int i = 0; i < nr_maps; ++i)
4772 dump_mmap_release (&maps[i]);
4773 return ret;
4774}
4775
4776static void
4777dump_mmap_release_vm (struct dump_memory_map *map)
4778{
4779 if (map->spec.fd < 0)
4780 dump_anonymous_release (map->mapping, map->spec.size);
4781 else
4782 dump_unmap_file (map->mapping, map->spec.size);
4783}
4784
4785static bool
4786needs_mmap_retry_p (void)
4787{
4788#if defined (CYGWIN) || VM_SUPPORTED == VM_MS_WINDOWS
4789 return true;
4790#else
4791 return false;
4792#endif
4793}
4794
4795static bool
4796dump_mmap_contiguous_vm (
4797 struct dump_memory_map *maps,
4798 int nr_maps,
4799 size_t total_size)
4800{
4801 bool ret = false;
4802 void *resv = NULL;
4803 bool retry = false;
4804 const bool need_retry = needs_mmap_retry_p ();
4805
4806 do
4807 {
4808 if (retry)
4809 {
4810 eassert (need_retry);
4811 retry = false;
4812 for (int i = 0; i < nr_maps; ++i)
4813 dump_mmap_release (&maps[i]);
4814 }
4815
4816 eassert (resv == NULL);
4817 resv = dump_anonymous_allocate (NULL,
4818 total_size,
4819 DUMP_MEMORY_ACCESS_NONE);
4820 if (!resv)
4821 goto out;
4822
4823 char *mem = resv;
4824
4825 if (need_retry)
4826 {
4827 /* Windows lacks atomic mapping replace; need to release the
4828 reservation so we can allocate within it. Will retry the
4829 loop if someone squats on our address space before we can
4830 finish allocation. On POSIX systems, we leave the
4831 reservation around for atomicity. */
4832 dump_anonymous_release (resv, total_size);
4833 resv = NULL;
4834 }
4835
4836 for (int i = 0; i < nr_maps; ++i)
4837 {
4838 struct dump_memory_map *map = &maps[i];
4839 const struct dump_memory_map_spec spec = map->spec;
4840 if (!spec.size)
4841 continue;
4842
4843 if (spec.fd < 0)
4844 map->mapping = dump_anonymous_allocate (
4845 mem, spec.size, spec.protection);
4846 else
4847 map->mapping = dump_map_file (
4848 mem, spec.fd, spec.offset, spec.size, spec.protection);
4849 mem += spec.size;
4850 if (need_retry &&
4851 map->mapping == NULL &&
4852 (errno == EBUSY
4853#ifdef CYGWIN
4854 || errno == EINVAL
4855#endif
4856 ))
4857 {
4858 retry = true;
4859 continue;
4860 }
4861 if (map->mapping == NULL)
4862 goto out;
4863 map->release = dump_mmap_release_vm;
4864 }
4865 }
4866 while (retry);
4867
4868 ret = true;
4869 resv = NULL;
4870 out:
4871 if (resv)
4872 dump_anonymous_release (resv, total_size);
4873 if (!ret)
4874 {
4875 for (int i = 0; i < nr_maps; ++i)
4876 {
4877 if (need_retry)
4878 dump_mmap_reset (&maps[i]);
4879 else
4880 dump_mmap_release (&maps[i]);
4881 }
4882 }
4883 return ret;
4884}
4885
4886/* Map a range of addresses into a chunk of contiguous memory.
4887
4888 Each dump_memory_map structure describes how to fill the
4889 corresponding range of memory. On input, all members except MAPPING
4890 are valid. On output, MAPPING contains the location of the given
4891 chunk of memory. The MAPPING for MAPS[N] is MAPS[N-1].mapping +
4892 MAPS[N-1].size.
4893
4894 Each mapping SIZE must be a multiple of the system page size except
4895 for the last mapping.
4896
4897 Return true on success or false on failure with errno set. */
4898static bool
4899dump_mmap_contiguous (
4900 struct dump_memory_map *maps,
4901 int nr_maps)
4902{
4903 if (!nr_maps)
4904 return true;
4905
4906 size_t total_size = 0;
4907 int worst_case_page_size = dump_get_page_size ();
4908
4909 for (int i = 0; i < nr_maps; ++i)
4910 {
4911 eassert (maps[i].mapping == NULL);
4912 eassert (maps[i].release == NULL);
4913 eassert (maps[i].private == NULL);
4914 if (i != nr_maps - 1)
4915 eassert (maps[i].spec.size % worst_case_page_size == 0);
4916 total_size += maps[i].spec.size;
4917 }
4918
4919 return (VM_SUPPORTED ?
4920 dump_mmap_contiguous_vm :
4921 dump_mmap_contiguous_heap)
4922 (maps, nr_maps, total_size);
4923}
4924
4925typedef uint_fast32_t dump_bitset_word;
4926
4927struct dump_bitset {
4928 dump_bitset_word *restrict bits;
4929 ptrdiff_t number_words;
4930};
4931
4932static bool
4933dump_bitset_init (struct dump_bitset *bitset, size_t number_bits)
4934{
4935 memset (bitset, 0, sizeof (*bitset));
4936 int xword_size = sizeof (bitset->bits[0]);
4937 int bits_per_word = xword_size * CHAR_BIT;
4938 ptrdiff_t words_needed = DIVIDE_ROUND_UP (number_bits, bits_per_word);
4939 bitset->number_words = words_needed;
4940 bitset->bits = calloc (words_needed, xword_size);
4941 return bitset->bits != NULL;
4942}
4943
4944static void
4945dump_bitset_destroy (struct dump_bitset *bitset)
4946{
4947 free (bitset->bits);
4948}
4949
4950static dump_bitset_word *
4951dump_bitset__bit_slot (const struct dump_bitset *bitset,
4952 size_t bit_number)
4953{
4954 int xword_size = sizeof (bitset->bits[0]);
4955 int bits_per_word = xword_size * CHAR_BIT;
4956 ptrdiff_t word_number = bit_number / bits_per_word;
4957 eassert (word_number < bitset->number_words);
4958 return &bitset->bits[word_number];
4959}
4960
4961static bool
4962dump_bitset_bit_set_p (const struct dump_bitset *bitset,
4963 size_t bit_number)
4964{
4965 unsigned xword_size = sizeof (bitset->bits[0]);
4966 unsigned bits_per_word = xword_size * CHAR_BIT;
4967 dump_bitset_word bit = 1;
4968 bit <<= bit_number % bits_per_word;
4969 return *dump_bitset__bit_slot (bitset, bit_number) & bit;
4970}
4971
4972static void
4973dump_bitset__set_bit_value (struct dump_bitset *bitset,
4974 size_t bit_number,
4975 bool bit_is_set)
4976{
4977 int xword_size = sizeof (bitset->bits[0]);
4978 int bits_per_word = xword_size * CHAR_BIT;
4979 dump_bitset_word * slot = dump_bitset__bit_slot (bitset, bit_number);
4980 dump_bitset_word bit = 1;
4981 bit <<= bit_number % bits_per_word;
4982 if (bit_is_set)
4983 *slot = *slot | bit;
4984 else
4985 *slot = *slot & ~bit;
4986}
4987
4988static void
4989dump_bitset_set_bit (struct dump_bitset *bitset, size_t bit_number)
4990{
4991 dump_bitset__set_bit_value (bitset, bit_number, true);
4992}
4993
4994static void
4995dump_bitset_clear (struct dump_bitset *bitset)
4996{
4997 int xword_size = sizeof (bitset->bits[0]);
4998 memset (bitset->bits, 0, bitset->number_words * xword_size);
4999}
5000
5001struct pdumper_loaded_dump_private
5002{
5003 /* Copy of the header we read from the dump. */
5004 struct dump_header header;
5005 /* Mark bits for objects in the dump; used during GC. */
5006 struct dump_bitset mark_bits;
5007 /* Time taken to load the dump. */
5008 double load_time;
5009 /* Dump file name. */
5010 char *dump_filename;
5011};
5012
5013struct pdumper_loaded_dump dump_public;
5014struct pdumper_loaded_dump_private dump_private;
5015
5016/* Return a pointer to offset OFFSET within the dump, which begins at
5017 DUMP_BASE. DUMP_BASE must be equal to the current dump load
5018 location; it's passed as a parameter for efficiency.
5019
5020 The returned pointer points to the primary memory image of the
5021 currently-loaded dump file. The entire dump file is accessible
5022 using this function. */
5023static void *
5024dump_ptr (uintptr_t dump_base, dump_off offset)
5025{
5026 eassert (dump_base == dump_public.start);
5027 eassert (0 <= offset);
5028 eassert (dump_public.start + offset < dump_public.end);
5029 return (char *)dump_base + offset;
5030}
5031
5032/* Read a pointer-sized word of memory at OFFSET within the dump,
5033 which begins at DUMP_BASE. DUMP_BASE must be equal to the current
5034 dump load location; it's passed as a parameter for efficiency. */
5035static uintptr_t
5036dump_read_word_from_dump (uintptr_t dump_base, dump_off offset)
5037{
5038 uintptr_t value;
5039 /* The compiler optimizes this memcpy into a read. */
5040 memcpy (&value, dump_ptr (dump_base, offset), sizeof (value));
5041 return value;
5042}
5043
5044/* Write a word to the dump. DUMP_BASE and OFFSET are as for
5045 dump_read_word_from_dump; VALUE is the word to write at the given
5046 offset. */
5047static void
5048dump_write_word_to_dump (uintptr_t dump_base,
5049 dump_off offset,
5050 uintptr_t value)
5051{
5052 /* The compiler optimizes this memcpy into a write. */
5053 memcpy (dump_ptr (dump_base, offset), &value, sizeof (value));
5054}
5055
5056/* Write a Lisp_Object to the dump. DUMP_BASE and OFFSET are as for
5057 dump_read_word_from_dump; VALUE is the Lisp_Object to write at the
5058 given offset. */
5059static void
5060dump_write_lv_to_dump (uintptr_t dump_base,
5061 dump_off offset,
5062 Lisp_Object value)
5063{
5064 /* The compiler optimizes this memcpy into a write. */
5065 memcpy (dump_ptr (dump_base, offset), &value, sizeof (value));
5066}
5067
5068/* Search for a relocation given a relocation target.
5069
5070 DUMP is the dump metadata structure. TABLE is the relocation table
5071 to search. KEY is the dump offset to find. Return the relocation
5072 RELOC such that RELOC.offset is the smallest RELOC.offset that
5073 satisfies the constraint KEY <= RELOC.offset --- that is, return
5074 the first relocation at KEY or after KEY. Return NULL if no such
5075 relocation exists. */
5076static const struct dump_reloc *
5077dump_find_relocation (const struct dump_table_locator *const table,
5078 const dump_off key)
5079{
5080 const struct dump_reloc *const relocs = dump_ptr (
5081 dump_public.start, table->offset);
5082 const struct dump_reloc *found = NULL;
5083 ptrdiff_t idx_left = 0;
5084 ptrdiff_t idx_right = table->nr_entries;
5085
5086 eassert (key >= 0);
5087
5088 while (idx_left < idx_right)
5089 {
5090 const ptrdiff_t idx_mid = idx_left + (idx_right - idx_left) / 2;
5091 const struct dump_reloc *mid = &relocs[idx_mid];
5092 if (key > dump_reloc_get_offset (*mid))
5093 idx_left = idx_mid + 1;
5094 else
5095 {
5096 found = mid;
5097 idx_right = idx_mid;
5098 if (idx_right <= idx_left ||
5099 key > dump_reloc_get_offset (relocs[idx_right - 1]))
5100 break;
5101 }
5102 }
5103
5104 return found;
5105}
5106
5107static bool
5108dump_loaded_p (void)
5109{
5110 return dump_public.start != 0;
5111}
5112
5113bool
5114pdumper_cold_object_p_impl (const void *obj)
5115{
5116 eassert (pdumper_object_p (obj));
5117 eassert (pdumper_object_p_precise (obj));
5118 dump_off offset = ptrdiff_t_to_dump_off (
5119 (uintptr_t) obj - dump_public.start);
5120 return offset >= dump_private.header.cold_start;
5121}
5122
5123enum Lisp_Type
5124pdumper_find_object_type_impl (const void *obj)
5125{
5126 eassert (pdumper_object_p (obj));
5127 dump_off offset = ptrdiff_t_to_dump_off (
5128 (uintptr_t) obj - dump_public.start);
5129 if (offset % DUMP_ALIGNMENT != 0)
5130 return PDUMPER_NO_OBJECT;
5131 const struct dump_reloc *reloc =
5132 dump_find_relocation (&dump_private.header.object_starts, offset);
5133 return (reloc != NULL && dump_reloc_get_offset (*reloc) == offset)
5134 ? (enum Lisp_Type) reloc->type
5135 : PDUMPER_NO_OBJECT;
5136}
5137
5138bool
5139pdumper_marked_p_impl (const void *obj)
5140{
5141 eassert (pdumper_object_p (obj));
5142 ptrdiff_t offset = (uintptr_t) obj - dump_public.start;
5143 eassert (offset % DUMP_ALIGNMENT == 0);
5144 eassert (offset < dump_private.header.cold_start);
5145 eassert (offset < dump_private.header.discardable_start);
5146 ptrdiff_t bitno = offset / DUMP_ALIGNMENT;
5147 return dump_bitset_bit_set_p (&dump_private.mark_bits, bitno);
5148}
5149
5150void
5151pdumper_set_marked_impl (const void *obj)
5152{
5153 eassert (pdumper_object_p (obj));
5154 ptrdiff_t offset = (uintptr_t) obj - dump_public.start;
5155 eassert (offset % DUMP_ALIGNMENT == 0);
5156 eassert (offset < dump_private.header.cold_start);
5157 eassert (offset < dump_private.header.discardable_start);
5158 ptrdiff_t bitno = offset / DUMP_ALIGNMENT;
5159 dump_bitset_set_bit (&dump_private.mark_bits, bitno);
5160}
5161
5162void
5163pdumper_clear_marks_impl (void)
5164{
5165 dump_bitset_clear (&dump_private.mark_bits);
5166}
5167
5168static ssize_t
5169dump_read_all (int fd, void *buf, size_t bytes_to_read)
5170{
5171 /* We don't want to use emacs_read, since that relies on the lisp
5172 world, and we're not in the lisp world yet. */
5173 eassert (bytes_to_read <= SSIZE_MAX);
5174 size_t bytes_read = 0;
5175 while (bytes_read < bytes_to_read)
5176 {
5177 /* Some platforms accept only int-sized values to read. */
5178 unsigned chunk_to_read = INT_MAX;
5179 if (bytes_to_read - bytes_read < chunk_to_read)
5180 chunk_to_read = (unsigned)(bytes_to_read - bytes_read);
5181 ssize_t chunk =
5182 read (fd, (char*) buf + bytes_read, chunk_to_read);
5183 if (chunk < 0)
5184 return chunk;
5185 if (chunk == 0)
5186 break;
5187 bytes_read += chunk;
5188 }
5189
5190 return bytes_read;
5191}
5192
5193/* Return the number of bytes written when we perform the given
5194 relocation. */
5195static int
5196dump_reloc_size (const struct dump_reloc reloc)
5197{
5198 if (sizeof (Lisp_Object) == sizeof (void*))
5199 return sizeof (Lisp_Object);
5200 if (reloc.type == RELOC_DUMP_TO_EMACS_PTR_RAW ||
5201 reloc.type == RELOC_DUMP_TO_DUMP_PTR_RAW)
5202 return sizeof (void*);
5203 return sizeof (Lisp_Object);
5204}
5205
5206static Lisp_Object
5207dump_make_lv_from_reloc (
5208 const uintptr_t dump_base,
5209 const struct dump_reloc reloc)
5210{
5211 const dump_off reloc_offset = dump_reloc_get_offset (reloc);
5212 uintptr_t value = dump_read_word_from_dump (dump_base, reloc_offset);
5213 enum Lisp_Type lisp_type;
5214
5215 if (RELOC_DUMP_TO_DUMP_LV <= reloc.type &&
5216 reloc.type < RELOC_DUMP_TO_EMACS_LV)
5217 {
5218 lisp_type = reloc.type - RELOC_DUMP_TO_DUMP_LV;
5219 value += dump_base;
5220 eassert (pdumper_object_p ((void *) value));
5221 }
5222 else
5223 {
5224 eassert (RELOC_DUMP_TO_EMACS_LV <= reloc.type);
5225 eassert (reloc.type < RELOC_DUMP_TO_EMACS_LV + 8);
5226 lisp_type = reloc.type - RELOC_DUMP_TO_EMACS_LV;
5227 value += emacs_basis ();
5228 }
5229
5230 eassert (lisp_type != Lisp_Int0 && lisp_type != Lisp_Int1);
5231
5232 Lisp_Object lv;
5233 if (lisp_type == Lisp_Symbol)
5234 lv = make_lisp_symbol ((void *) value);
5235 else
5236 lv = make_lisp_ptr ((void *) value, lisp_type);
5237
5238 return lv;
5239}
5240
5241/* Actually apply a dump relocation. */
5242static inline void
5243dump_do_dump_relocation (
5244 const uintptr_t dump_base,
5245 const struct dump_reloc reloc)
5246{
5247 const dump_off reloc_offset = dump_reloc_get_offset (reloc);
5248
5249 /* We should never generate a relocation in the cold section. */
5250 eassert (reloc_offset < dump_private.header.cold_start);
5251
5252 switch (reloc.type)
5253 {
5254 case RELOC_DUMP_TO_EMACS_PTR_RAW:
5255 {
5256 uintptr_t value = dump_read_word_from_dump (dump_base, reloc_offset);
5257 eassert (dump_reloc_size (reloc) == sizeof (value));
5258 value += emacs_basis ();
5259 dump_write_word_to_dump (dump_base, reloc_offset, value);
5260 break;
5261 }
5262 case RELOC_DUMP_TO_DUMP_PTR_RAW:
5263 {
5264 uintptr_t value = dump_read_word_from_dump (dump_base, reloc_offset);
5265 eassert (dump_reloc_size (reloc) == sizeof (value));
5266 value += dump_base;
5267 dump_write_word_to_dump (dump_base, reloc_offset, value);
5268 break;
5269 }
5270 case RELOC_BIGNUM:
5271 {
5272 struct Lisp_Bignum *bignum = dump_ptr (dump_base, reloc_offset);
5273 struct bignum_reload_info reload_info;
5274 verify (sizeof (reload_info) <= sizeof (bignum->value));
5275 memcpy (&reload_info, &bignum->value, sizeof (reload_info));
5276 memset (&bignum->value, 0, sizeof (bignum->value));
5277 mpz_init (bignum->value);
5278 const mp_limb_t *limbs =
5279 dump_ptr (dump_base, reload_info.data_location);
5280 mpz_roinit_n (bignum->value, limbs, reload_info.nlimbs);
5281 break;
5282 }
5283 default: /* Lisp_Object in the dump; precise type in reloc.type */
5284 {
5285 Lisp_Object lv = dump_make_lv_from_reloc (dump_base, reloc);
5286 eassert (dump_reloc_size (reloc) == sizeof (lv));
5287 dump_write_lv_to_dump (dump_base, reloc_offset, lv);
5288 break;
5289 }
5290 }
5291}
5292
5293static void
5294dump_do_all_dump_relocations (
5295 const struct dump_header *const header,
5296 const uintptr_t dump_base)
5297{
5298 struct dump_reloc *r = dump_ptr (dump_base, header->dump_relocs.offset);
5299 dump_off nr_entries = header->dump_relocs.nr_entries;
5300 for (dump_off i = 0; i < nr_entries; ++i)
5301 dump_do_dump_relocation (dump_base, r[i]);
5302}
5303
5304static void
5305dump_do_emacs_relocation (
5306 const uintptr_t dump_base,
5307 const struct emacs_reloc reloc)
5308{
5309 ptrdiff_t pval;
5310 Lisp_Object lv;
5311
5312 switch (reloc.type)
5313 {
5314 case RELOC_EMACS_COPY_FROM_DUMP:
5315 eassume (reloc.length > 0);
5316 memcpy (emacs_ptr (reloc.emacs_offset),
5317 dump_ptr (dump_base, reloc.u.dump_offset),
5318 reloc.length);
5319 break;
5320 case RELOC_EMACS_IMMEDIATE:
5321 eassume (reloc.length > 0);
5322 eassume (reloc.length <= sizeof (reloc.u.immediate));
5323 memcpy (emacs_ptr (reloc.emacs_offset),
5324 &reloc.u.immediate,
5325 reloc.length);
5326 break;
5327 case RELOC_EMACS_DUMP_PTR_RAW:
5328 pval = reloc.u.dump_offset + dump_base;
5329 memcpy (emacs_ptr (reloc.emacs_offset), &pval, sizeof (pval));
5330 break;
5331 case RELOC_EMACS_EMACS_PTR_RAW:
5332 pval = reloc.u.emacs_offset2 + emacs_basis ();
5333 memcpy (emacs_ptr (reloc.emacs_offset), &pval, sizeof (pval));
5334 break;
5335 case RELOC_EMACS_DUMP_LV:
5336 case RELOC_EMACS_EMACS_LV:
5337 {
5338 /* Lisp_Float is the maximum lisp type. */
5339 eassume (reloc.length <= Lisp_Float);
5340 void *obj_ptr = reloc.type == RELOC_EMACS_DUMP_LV
5341 ? dump_ptr (dump_base, reloc.u.dump_offset)
5342 : emacs_ptr (reloc.u.emacs_offset2);
5343 if (reloc.length == Lisp_Symbol)
5344 lv = make_lisp_symbol (obj_ptr);
5345 else
5346 lv = make_lisp_ptr (obj_ptr, reloc.length);
5347 memcpy (emacs_ptr (reloc.emacs_offset), &lv, sizeof (lv));
5348 break;
5349 }
5350 default:
5351 fatal ("unrecognied relocation type %d", (int) reloc.type);
5352 }
5353}
5354
5355static void
5356dump_do_all_emacs_relocations (
5357 const struct dump_header *const header,
5358 const uintptr_t dump_base)
5359{
5360 const dump_off nr_entries = header->emacs_relocs.nr_entries;
5361 struct emacs_reloc *r = dump_ptr (dump_base, header->emacs_relocs.offset);
5362 for (dump_off i = 0; i < nr_entries; ++i)
5363 dump_do_emacs_relocation (dump_base, r[i]);
5364}
5365
5366enum dump_section
5367 {
5368 DS_HOT,
5369 DS_DISCARDABLE,
5370 DS_COLD,
5371 NUMBER_DUMP_SECTIONS,
5372 };
5373
5374/* Subtract two timespecs, yielding a difference in milliseconds. */
5375static double
5376subtract_timespec (struct timespec minuend, struct timespec subtrahend)
5377{
5378 return
5379 1000.0 * (double)(minuend.tv_sec - subtrahend.tv_sec)
5380 + (double)(minuend.tv_nsec - subtrahend.tv_nsec) / 1.0e6;
5381}
5382
5383/* Load a dump from DUMP_FILENAME. Return an error code.
5384
5385 N.B. We run very early in initialization, so we can't use lisp,
5386 unwinding, xmalloc, and so on. */
5387enum pdumper_load_result
5388pdumper_load (const char *dump_filename)
5389{
5390 enum pdumper_load_result err = PDUMPER_LOAD_ERROR;
5391
5392 int dump_fd = -1;
5393 intptr_t dump_size;
5394 struct stat stat;
5395 uintptr_t dump_base;
5396 int dump_page_size;
5397 dump_off adj_discardable_start;
5398
5399 struct dump_bitset mark_bits;
5400 bool free_mark_bits = false;
5401 size_t mark_bits_needed;
5402
5403 struct dump_header header_buf;
5404 struct dump_header *header = &header_buf;
5405 struct dump_memory_map sections[NUMBER_DUMP_SECTIONS];
5406
5407 const struct timespec start_time = current_timespec ();
5408 char *dump_filename_copy = NULL;
5409
5410 memset (&header_buf, 0, sizeof (header_buf));
5411 memset (&sections, 0, sizeof (sections));
5412
5413 /* Overwriting an initialized Lisp universe will not go well. */
5414 eassert (!initialized);
5415
5416 /* We can load only one dump. */
5417 eassert (!dump_loaded_p ());
5418
5419 err = PDUMPER_LOAD_FILE_NOT_FOUND;
5420 dump_fd = emacs_open (dump_filename, O_RDONLY, 0);
5421 if (dump_fd < 0)
5422 goto out;
5423
5424 err = PDUMPER_LOAD_FILE_NOT_FOUND;
5425 if (fstat (dump_fd, &stat) < 0)
5426 goto out;
5427
5428 err = PDUMPER_LOAD_BAD_FILE_TYPE;
5429 if (stat.st_size > INTPTR_MAX)
5430 goto out;
5431 dump_size = (intptr_t) stat.st_size;
5432
5433 err = PDUMPER_LOAD_BAD_FILE_TYPE;
5434 if (dump_size < sizeof (*header))
5435 goto out;
5436
5437 err = PDUMPER_LOAD_BAD_FILE_TYPE;
5438 if (dump_read_all (dump_fd,
5439 header,
5440 sizeof (*header)) < sizeof (*header))
5441 goto out;
5442
5443 if (memcmp (header->magic, dump_magic, sizeof (dump_magic)) != 0)
5444 {
5445 if (header->magic[0] == '!' &&
5446 ((header->magic[0] = dump_magic[0]),
5447 memcmp (header->magic, dump_magic, sizeof (dump_magic)) == 0))
5448 {
5449 err = PDUMPER_LOAD_FAILED_DUMP;
5450 goto out;
5451 }
5452 err = PDUMPER_LOAD_BAD_FILE_TYPE;
5453 goto out;
5454 }
5455
5456 err = PDUMPER_LOAD_VERSION_MISMATCH;
5457 verify (sizeof (header->fingerprint) == sizeof (fingerprint));
5458 if (memcmp (header->fingerprint, fingerprint, sizeof (fingerprint)) != 0)
5459 {
5460 dump_fingerprint ("desired fingerprint", fingerprint);
5461 dump_fingerprint ("found fingerprint", header->fingerprint);
5462 goto out;
5463 }
5464
5465 err = PDUMPER_LOAD_OOM;
5466 dump_filename_copy = strdup (dump_filename);
5467 if (!dump_filename_copy)
5468 goto out;
5469
5470 err = PDUMPER_LOAD_OOM;
5471
5472 adj_discardable_start = header->discardable_start;
5473 dump_page_size = dump_get_page_size ();
5474 /* Snap to next page boundary. */
5475 adj_discardable_start = ROUNDUP (
5476 adj_discardable_start,
5477 dump_page_size);
5478 eassert (adj_discardable_start % dump_page_size == 0);
5479 eassert (adj_discardable_start <= header->cold_start);
5480
5481 sections[DS_HOT].spec = (struct dump_memory_map_spec)
5482 {
5483 .fd = dump_fd,
5484 .size = adj_discardable_start,
5485 .offset = 0,
5486 .protection = DUMP_MEMORY_ACCESS_READWRITE,
5487 };
5488
5489 sections[DS_DISCARDABLE].spec = (struct dump_memory_map_spec)
5490 {
5491 .fd = dump_fd,
5492 .size = header->cold_start - adj_discardable_start,
5493 .offset = adj_discardable_start,
5494 .protection = DUMP_MEMORY_ACCESS_READWRITE,
5495 };
5496
5497 sections[DS_COLD].spec = (struct dump_memory_map_spec)
5498 {
5499 .fd = dump_fd,
5500 .size = dump_size - header->cold_start,
5501 .offset = header->cold_start,
5502 .protection = DUMP_MEMORY_ACCESS_READWRITE,
5503 };
5504
5505 if (!dump_mmap_contiguous (sections, ARRAYELTS (sections)))
5506 goto out;
5507
5508 err = PDUMPER_LOAD_ERROR;
5509 mark_bits_needed =
5510 DIVIDE_ROUND_UP (header->discardable_start, DUMP_ALIGNMENT);
5511 if (!dump_bitset_init (&mark_bits, mark_bits_needed))
5512 goto out;
5513 free_mark_bits = true;
5514
5515 /* Point of no return. */
5516 err = PDUMPER_LOAD_SUCCESS;
5517 dump_base = (uintptr_t) sections[DS_HOT].mapping;
5518 gflags.dumped_with_pdumper_ = true;
5519 free_mark_bits = false;
5520 dump_private.header = *header;
5521 dump_private.mark_bits = mark_bits;
5522 dump_public.start = dump_base;
5523 dump_public.end = dump_public.start + dump_size;
5524
5525 dump_do_all_dump_relocations (header, dump_base);
5526 dump_do_all_emacs_relocations (header, dump_base);
5527
5528 dump_mmap_discard_contents (&sections[DS_DISCARDABLE]);
5529 for (int i = 0; i < ARRAYELTS (sections); ++i)
5530 dump_mmap_reset (&sections[i]);
5531
5532 /* Run the functions Emacs registered for doing post-dump-load
5533 initialization. */
5534 for (int i = 0; i < nr_dump_hooks; ++i)
5535 dump_hooks[i] ();
5536 initialized = true;
5537
5538 dump_private.load_time = subtract_timespec (
5539 current_timespec (), start_time);
5540 dump_private.dump_filename = dump_filename_copy;
5541 dump_filename_copy = NULL;
5542
5543 out:
5544 for (int i = 0; i < ARRAYELTS (sections); ++i)
5545 dump_mmap_release (&sections[i]);
5546 if (free_mark_bits)
5547 dump_bitset_destroy (&mark_bits);
5548 if (dump_fd >= 0)
5549 emacs_close (dump_fd);
5550 free (dump_filename_copy);
5551 return err;
5552}
5553
5554DEFUN ("pdumper-stats",
5555 Fpdumper_stats, Spdumper_stats,
5556 0, 0, 0,
5557 doc: /* Return an alist of statistics about dump file that
5558 started this Emacs, if any. Nil if this Emacs was not
5559 started using a portable dumper dump file.*/)
5560 (void)
5561{
5562 if (!dumped_with_pdumper_p ())
5563 return Qnil;
5564
5565 return CALLN (
5566 Flist,
5567 Fcons (Qdumped_with_pdumper, Qt),
5568 Fcons (Qload_time, make_float (dump_private.load_time)),
5569 Fcons (Qdump_file_name,
5570 build_unibyte_string (dump_private.dump_filename)));
5571}
5572
5573#endif /* HAVE_PDUMPER */
5574
5575
5576
5577void
5578syms_of_pdumper (void)
5579{
5580#ifdef HAVE_PDUMPER
5581 defsubr (&Sdump_emacs_portable);
5582 defsubr (&Sdump_emacs_portable__sort_predicate);
5583 defsubr (&Sdump_emacs_portable__sort_predicate_copied);
5584 DEFSYM (Qdump_emacs_portable__sort_predicate,
5585 "dump-emacs-portable--sort-predicate");
5586 DEFSYM (Qdump_emacs_portable__sort_predicate_copied,
5587 "dump-emacs-portable--sort-predicate-copied");
5588 DEFSYM (Qdumped_with_pdumper, "dumped-with-pdumper");
5589 DEFSYM (Qload_time, "load-time");
5590 DEFSYM (Qdump_file_name, "dump-file-name");
5591 defsubr (&Spdumper_stats);
5592#endif /* HAVE_PDUMPER */
5593}
diff --git a/src/pdumper.h b/src/pdumper.h
new file mode 100644
index 00000000000..8ed4fc1cb3b
--- /dev/null
+++ b/src/pdumper.h
@@ -0,0 +1,267 @@
1/* Header file for the portable dumper.
2
3Copyright (C) 2016 Free Software Foundation,
4Inc.
5
6This file is part of GNU Emacs.
7
8GNU Emacs is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or (at
11your option) any later version.
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20
21#ifndef EMACS_PDUMPER_H
22#define EMACS_PDUMPER_H
23
24#include "lisp.h"
25
26INLINE_HEADER_BEGIN
27
28#define PDUMPER_NO_OBJECT ((enum Lisp_Type) -1)
29
30/* Indicate in source code that we're deliberately relying on pdumper
31 not preserving the given value. Compiles to nothing --- for humans
32 only. */
33#define PDUMPER_IGNORE(thing) ((void) &(thing))
34
35/* The portable dumper automatically preserves the Lisp heap and any C
36 variables to which the Lisp heap points. It doesn't know anything
37 about other C variables. The functions below allow code from other
38 parts of Emacs to tell the portable dumper about other bits of
39 information to preserve in dumped images.
40
41 These memory-records are themselves preserved in the dump, so call
42 the functions below only on the !initialized init path, just
43 like staticpro.
44
45 There are no special functions to preserve a global Lisp_Object.
46 You should just staticpro these. */
47
48/* Remember the value of THING in dumped images. THING must not
49 contain any pointers or Lisp_Object variables: these values are not
50 valid across dump and load. */
51#define PDUMPER_REMEMBER_SCALAR(thing) \
52 pdumper_remember_scalar (&(thing), sizeof (thing))
53
54extern void pdumper_remember_scalar_impl (void *data, ptrdiff_t nbytes);
55
56INLINE
57void
58pdumper_remember_scalar (void *data, ptrdiff_t nbytes)
59{
60#ifdef HAVE_PDUMPER
61 pdumper_remember_scalar_impl (data, nbytes);
62#else
63 (void) data;
64 (void) nbytes;
65#endif
66}
67
68extern void pdumper_remember_lv_ptr_raw_impl (
69 void *ptr, enum Lisp_Type type);
70
71/* Remember the pointer at *PTR. *PTR must be null or point to a Lisp
72 object. TYPE is the rough type of Lisp object to which *PTR
73 points. */
74INLINE
75void
76pdumper_remember_lv_ptr_raw (void* ptr, enum Lisp_Type type)
77{
78#ifdef HAVE_PDUMPER
79 pdumper_remember_lv_ptr_raw_impl (ptr, type);
80#else
81 (void) ptr;
82 (void) type;
83#endif
84}
85
86typedef void (*pdumper_hook)(void);
87extern void pdumper_do_now_and_after_load_impl (pdumper_hook hook);
88
89INLINE void
90pdumper_do_now_and_after_load (pdumper_hook hook)
91{
92#ifdef HAVE_PDUMPER
93 pdumper_do_now_and_after_load_impl (hook);
94#else
95 hook ();
96#endif
97}
98
99/* Macros useful in pdumper callback functions. Assign a value if
100 we're loading a dump and the value needs to be reset to its
101 original value, and if we're initializing for the first time,
102 assert that the value has the expected original value. */
103
104#define PDUMPER_RESET(variable, value) \
105 do { \
106 if (dumped_with_pdumper_p ()) \
107 (variable) = (value); \
108 else \
109 eassert ((variable) == (value)); \
110 } while (0)
111
112#define PDUMPER_RESET_LV(variable, value) \
113 do { \
114 if (dumped_with_pdumper_p ()) \
115 (variable) = (value); \
116 else \
117 eassert (EQ ((variable), (value))); \
118 } while (0)
119
120/* Actually load a dump. */
121
122enum pdumper_load_result
123 {
124 PDUMPER_LOAD_SUCCESS,
125 PDUMPER_NOT_LOADED /* Not returned: useful for callers */,
126 PDUMPER_LOAD_FILE_NOT_FOUND,
127 PDUMPER_LOAD_BAD_FILE_TYPE,
128 PDUMPER_LOAD_FAILED_DUMP,
129 PDUMPER_LOAD_OOM,
130 PDUMPER_LOAD_VERSION_MISMATCH,
131 PDUMPER_LOAD_ERROR,
132 };
133
134enum pdumper_load_result pdumper_load (const char *dump_filename);
135
136struct pdumper_loaded_dump {
137 uintptr_t start;
138 uintptr_t end;
139};
140
141#ifdef HAVE_PDUMPER
142extern struct pdumper_loaded_dump dump_public;
143#endif
144
145/* Return whether the OBJ points somewhere into the loaded dump image.
146 Works even when we have no dump loaded --- in this case, it just
147 returns false. */
148INLINE _GL_ATTRIBUTE_CONST
149bool
150pdumper_object_p (const void *obj)
151{
152#ifdef HAVE_PDUMPER
153 uintptr_t obj_addr = (uintptr_t) obj;
154 return dump_public.start <= obj_addr && obj_addr < dump_public.end;
155#else
156 (void) obj;
157 return false;
158#endif
159}
160
161extern bool pdumper_cold_object_p_impl (const void *obj);
162
163/* Return whether the OBJ is in the cold section of the dump.
164 Only bool-vectors and floats should end up there.
165 pdumper_object_p() and pdumper_object_p_precise() must have
166 returned true for OBJ before calling this function. */
167INLINE _GL_ATTRIBUTE_CONST
168bool
169pdumper_cold_object_p (const void *obj)
170{
171#ifdef HAVE_PDUMPER
172 return pdumper_cold_object_p_impl (obj);
173#else
174 (void) obj;
175 return false;
176#endif
177}
178
179
180extern enum Lisp_Type pdumper_find_object_type_impl (const void *obj);
181
182/* Return the type of the dumped object that starts at OBJ. It is a
183 programming error to call this routine for an OBJ for which
184 pdumper_object_p would return false. */
185INLINE _GL_ATTRIBUTE_CONST
186enum Lisp_Type
187pdumper_find_object_type (const void *obj)
188{
189#ifdef HAVE_PDUMPER
190 return pdumper_find_object_type_impl (obj);
191#else
192 (void) obj;
193 emacs_abort ();
194#endif
195}
196
197/* Return whether OBJ points exactly to the start of some object in
198 the loaded dump image. It is a programming error to call this
199 routine for an OBJ for which pdumper_object_p would return
200 false. */
201INLINE _GL_ATTRIBUTE_CONST
202bool
203pdumper_object_p_precise (const void *obj)
204{
205#ifdef HAVE_PDUMPER
206 return pdumper_find_object_type (obj) != PDUMPER_NO_OBJECT;
207#else
208 (void) obj;
209 emacs_abort ();
210#endif
211}
212
213extern bool pdumper_marked_p_impl (const void *obj);
214
215/* Return whether OBJ is marked according to the portable dumper.
216 It is an error to call this routine for an OBJ for which
217 pdumper_object_p_precise would return false. */
218INLINE
219bool
220pdumper_marked_p (const void *obj)
221{
222#ifdef HAVE_PDUMPER
223 return pdumper_marked_p_impl (obj);
224#else
225 (void) obj;
226 emacs_abort ();
227#endif
228}
229
230extern void pdumper_set_marked_impl (const void *obj);
231
232/* Set the pdumper mark bit for OBJ. It is a programming error to
233 call this function with an OBJ for which pdumper_object_p_precise
234 would return false. */
235INLINE
236void
237pdumper_set_marked (const void *obj)
238{
239#ifdef HAVE_PDUMPER
240 pdumper_set_marked_impl (obj);
241#else
242 (void) obj;
243 emacs_abort ();
244#endif
245}
246
247extern void pdumper_clear_marks_impl (void);
248
249/* Clear all the mark bits for pdumper objects. */
250INLINE
251void
252pdumper_clear_marks (void)
253{
254#ifdef HAVE_PDUMPER
255 pdumper_clear_marks_impl ();
256#endif
257}
258
259/* Handle a page fault that occurs when we access the portable dumper
260 mapping. Return true iff the fault should be considered handled
261 and execution should resume. */
262bool pdumper_handle_page_fault (void *fault_addr_ptr);
263
264void syms_of_pdumper (void);
265
266INLINE_HEADER_END
267#endif
diff --git a/src/process.c b/src/process.c
index edf633e512e..06555bac4c0 100644
--- a/src/process.c
+++ b/src/process.c
@@ -8028,9 +8028,7 @@ init_process_emacs (int sockfd)
8028 8028
8029 inhibit_sentinels = 0; 8029 inhibit_sentinels = 0;
8030 8030
8031#ifndef CANNOT_DUMP 8031 if (!will_dump_with_unexec_p ())
8032 if (! noninteractive || initialized)
8033#endif
8034 { 8032 {
8035#if defined HAVE_GLIB && !defined WINDOWSNT 8033#if defined HAVE_GLIB && !defined WINDOWSNT
8036 /* Tickle glib's child-handling code. Ask glib to wait for Emacs itself; 8034 /* Tickle glib's child-handling code. Ask glib to wait for Emacs itself;
diff --git a/src/profiler.c b/src/profiler.c
index ff4143383ce..76245750ada 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
21#include "lisp.h" 21#include "lisp.h"
22#include "syssignal.h" 22#include "syssignal.h"
23#include "systime.h" 23#include "systime.h"
24#include "pdumper.h"
24 25
25/* Return A + B, but return the maximum fixnum if the result would overflow. 26/* Return A + B, but return the maximum fixnum if the result would overflow.
26 Assume A and B are nonnegative and in fixnum range. */ 27 Assume A and B are nonnegative and in fixnum range. */
@@ -570,6 +571,8 @@ hashfn_profiler (struct hash_table_test *ht, Lisp_Object bt)
570 return XHASH (bt); 571 return XHASH (bt);
571} 572}
572 573
574static void syms_of_profiler_for_pdumper (void);
575
573void 576void
574syms_of_profiler (void) 577syms_of_profiler (void)
575{ 578{
@@ -608,4 +611,22 @@ to make room for new entries. */);
608 defsubr (&Sprofiler_memory_stop); 611 defsubr (&Sprofiler_memory_stop);
609 defsubr (&Sprofiler_memory_running_p); 612 defsubr (&Sprofiler_memory_running_p);
610 defsubr (&Sprofiler_memory_log); 613 defsubr (&Sprofiler_memory_log);
614
615 pdumper_do_now_and_after_load (syms_of_profiler_for_pdumper);
616}
617
618static void
619syms_of_profiler_for_pdumper (void)
620{
621 if (dumped_with_pdumper_p ())
622 {
623 cpu_log = Qnil;
624 memory_log = Qnil;
625 }
626 else
627 {
628 eassert (NILP (cpu_log));
629 eassert (NILP (memory_log));
630 }
631
611} 632}
diff --git a/src/search.c b/src/search.c
index f97dbe73341..059f8fc4d2e 100644
--- a/src/search.c
+++ b/src/search.c
@@ -29,6 +29,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
29#include "region-cache.h" 29#include "region-cache.h"
30#include "blockinput.h" 30#include "blockinput.h"
31#include "intervals.h" 31#include "intervals.h"
32#include "pdumper.h"
32 33
33#include "regex-emacs.h" 34#include "regex-emacs.h"
34 35
@@ -3386,26 +3387,17 @@ the buffer. If the buffer doesn't have a cache, the value is nil. */)
3386} 3387}
3387 3388
3388 3389
3390static void syms_of_search_for_pdumper (void);
3391
3389void 3392void
3390syms_of_search (void) 3393syms_of_search (void)
3391{ 3394{
3392 register int i; 3395 for (int i = 0; i < REGEXP_CACHE_SIZE; ++i)
3393
3394 for (i = 0; i < REGEXP_CACHE_SIZE; ++i)
3395 { 3396 {
3396 searchbufs[i].buf.allocated = 100;
3397 searchbufs[i].buf.buffer = xmalloc (100);
3398 searchbufs[i].buf.fastmap = searchbufs[i].fastmap;
3399 searchbufs[i].regexp = Qnil;
3400 searchbufs[i].f_whitespace_regexp = Qnil;
3401 searchbufs[i].busy = false;
3402 searchbufs[i].syntax_table = Qnil;
3403 staticpro (&searchbufs[i].regexp); 3397 staticpro (&searchbufs[i].regexp);
3404 staticpro (&searchbufs[i].f_whitespace_regexp); 3398 staticpro (&searchbufs[i].f_whitespace_regexp);
3405 staticpro (&searchbufs[i].syntax_table); 3399 staticpro (&searchbufs[i].syntax_table);
3406 searchbufs[i].next = (i == REGEXP_CACHE_SIZE-1 ? 0 : &searchbufs[i+1]);
3407 } 3400 }
3408 searchbuf_head = &searchbufs[0];
3409 3401
3410 /* Error condition used for failing searches. */ 3402 /* Error condition used for failing searches. */
3411 DEFSYM (Qsearch_failed, "search-failed"); 3403 DEFSYM (Qsearch_failed, "search-failed");
@@ -3476,4 +3468,23 @@ is to bind it with `let' around a small expression. */);
3476 defsubr (&Sset_match_data); 3468 defsubr (&Sset_match_data);
3477 defsubr (&Sregexp_quote); 3469 defsubr (&Sregexp_quote);
3478 defsubr (&Snewline_cache_check); 3470 defsubr (&Snewline_cache_check);
3471
3472 pdumper_do_now_and_after_load (syms_of_search_for_pdumper);
3473}
3474
3475static void
3476syms_of_search_for_pdumper (void)
3477{
3478 for (int i = 0; i < REGEXP_CACHE_SIZE; ++i)
3479 {
3480 searchbufs[i].buf.allocated = 100;
3481 searchbufs[i].buf.buffer = xmalloc (100);
3482 searchbufs[i].buf.fastmap = searchbufs[i].fastmap;
3483 searchbufs[i].regexp = Qnil;
3484 searchbufs[i].f_whitespace_regexp = Qnil;
3485 searchbufs[i].busy = false;
3486 searchbufs[i].syntax_table = Qnil;
3487 searchbufs[i].next = (i == REGEXP_CACHE_SIZE-1 ? 0 : &searchbufs[i+1]);
3488 }
3489 searchbuf_head = &searchbufs[0];
3479} 3490}
diff --git a/src/sheap.c b/src/sheap.c
index f019c7ee3c4..015ee5786ff 100644
--- a/src/sheap.c
+++ b/src/sheap.c
@@ -31,7 +31,6 @@ static int debug_sheap;
31 31
32char bss_sbrk_buffer[STATIC_HEAP_SIZE]; 32char bss_sbrk_buffer[STATIC_HEAP_SIZE];
33char *max_bss_sbrk_ptr; 33char *max_bss_sbrk_ptr;
34bool bss_sbrk_did_unexec;
35 34
36void * 35void *
37bss_sbrk (ptrdiff_t request_size) 36bss_sbrk (ptrdiff_t request_size)
diff --git a/src/sheap.h b/src/sheap.h
index 27300814b07..a5653288f5b 100644
--- a/src/sheap.h
+++ b/src/sheap.h
@@ -27,5 +27,4 @@ enum { STATIC_HEAP_SIZE = sizeof (Lisp_Object) << 22 };
27 27
28extern char bss_sbrk_buffer[STATIC_HEAP_SIZE]; 28extern char bss_sbrk_buffer[STATIC_HEAP_SIZE];
29extern char *max_bss_sbrk_ptr; 29extern char *max_bss_sbrk_ptr;
30extern bool bss_sbrk_did_unexec;
31extern void *bss_sbrk (ptrdiff_t); 30extern void *bss_sbrk (ptrdiff_t);
diff --git a/src/syntax.c b/src/syntax.c
index ba8f5fcfa9e..4616ae296f8 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -3730,9 +3730,6 @@ syms_of_syntax (void)
3730 staticpro (&gl_state.current_syntax_table); 3730 staticpro (&gl_state.current_syntax_table);
3731 staticpro (&gl_state.old_prop); 3731 staticpro (&gl_state.old_prop);
3732 3732
3733 /* Defined in regex-emacs.c. */
3734 staticpro (&re_match_object);
3735
3736 DEFSYM (Qscan_error, "scan-error"); 3733 DEFSYM (Qscan_error, "scan-error");
3737 Fput (Qscan_error, Qerror_conditions, 3734 Fput (Qscan_error, Qerror_conditions,
3738 listn (CONSTYPE_PURE, 2, Qscan_error, Qerror)); 3735 listn (CONSTYPE_PURE, 2, Qscan_error, Qerror));
diff --git a/src/sysdep.c b/src/sysdep.c
index a477ec892ec..f8594d6a915 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -270,7 +270,7 @@ get_current_dir_name_or_unreachable (void)
270 270
271# if HAVE_GET_CURRENT_DIR_NAME && !BROKEN_GET_CURRENT_DIR_NAME 271# if HAVE_GET_CURRENT_DIR_NAME && !BROKEN_GET_CURRENT_DIR_NAME
272# ifdef HYBRID_MALLOC 272# ifdef HYBRID_MALLOC
273 bool use_libc = bss_sbrk_did_unexec; 273 bool use_libc = will_dump_with_unexec_p ();
274# else 274# else
275 bool use_libc = true; 275 bool use_libc = true;
276# endif 276# endif
@@ -1893,7 +1893,7 @@ handle_sigsegv (int sig, siginfo_t *siginfo, void *arg)
1893/* Return true if we have successfully set up SIGSEGV handler on alternate 1893/* Return true if we have successfully set up SIGSEGV handler on alternate
1894 stack. Otherwise we just treat SIGSEGV among the rest of fatal signals. */ 1894 stack. Otherwise we just treat SIGSEGV among the rest of fatal signals. */
1895 1895
1896static bool 1896bool
1897init_sigsegv (void) 1897init_sigsegv (void)
1898{ 1898{
1899 struct sigaction sa; 1899 struct sigaction sa;
@@ -1908,12 +1908,15 @@ init_sigsegv (void)
1908 sigfillset (&sa.sa_mask); 1908 sigfillset (&sa.sa_mask);
1909 sa.sa_sigaction = handle_sigsegv; 1909 sa.sa_sigaction = handle_sigsegv;
1910 sa.sa_flags = SA_SIGINFO | SA_ONSTACK | emacs_sigaction_flags (); 1910 sa.sa_flags = SA_SIGINFO | SA_ONSTACK | emacs_sigaction_flags ();
1911 return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1; 1911 if (sigaction (SIGSEGV, &sa, NULL) < 0)
1912 return 0;
1913
1914 return 1;
1912} 1915}
1913 1916
1914#else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */ 1917#else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */
1915 1918
1916static bool 1919bool
1917init_sigsegv (void) 1920init_sigsegv (void)
1918{ 1921{
1919 return 0; 1922 return 0;
@@ -1963,7 +1966,7 @@ maybe_fatal_sig (int sig)
1963} 1966}
1964 1967
1965void 1968void
1966init_signals (bool dumping) 1969init_signals (void)
1967{ 1970{
1968 struct sigaction thread_fatal_action; 1971 struct sigaction thread_fatal_action;
1969 struct sigaction action; 1972 struct sigaction action;
@@ -2114,7 +2117,7 @@ init_signals (bool dumping)
2114 /* Don't alter signal handlers if dumping. On some machines, 2117 /* Don't alter signal handlers if dumping. On some machines,
2115 changing signal handlers sets static data that would make signals 2118 changing signal handlers sets static data that would make signals
2116 fail to work right when the dumped Emacs is run. */ 2119 fail to work right when the dumped Emacs is run. */
2117 if (dumping) 2120 if (will_dump_p ())
2118 return; 2121 return;
2119 2122
2120 sigfillset (&process_fatal_action.sa_mask); 2123 sigfillset (&process_fatal_action.sa_mask);
diff --git a/src/syssignal.h b/src/syssignal.h
index 01fb41feded..ecd6c9cc8c2 100644
--- a/src/syssignal.h
+++ b/src/syssignal.h
@@ -22,7 +22,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
22 22
23#include <signal.h> 23#include <signal.h>
24 24
25extern void init_signals (bool); 25extern void init_signals (void);
26extern bool init_sigsegv (void);
26extern void block_child_signal (sigset_t *); 27extern void block_child_signal (sigset_t *);
27extern void unblock_child_signal (sigset_t const *); 28extern void unblock_child_signal (sigset_t const *);
28extern void block_interrupt_signal (sigset_t *); 29extern void block_interrupt_signal (sigset_t *);
diff --git a/src/systime.h b/src/systime.h
index 1812f073f35..9080cd2bba1 100644
--- a/src/systime.h
+++ b/src/systime.h
@@ -93,7 +93,7 @@ extern bool list4_to_timespec (Lisp_Object, Lisp_Object, Lisp_Object,
93 Lisp_Object, struct timespec *); 93 Lisp_Object, struct timespec *);
94extern struct timespec lisp_time_argument (Lisp_Object); 94extern struct timespec lisp_time_argument (Lisp_Object);
95extern _Noreturn void time_overflow (void); 95extern _Noreturn void time_overflow (void);
96extern void init_timefns (bool); 96extern void init_timefns (void);
97extern void syms_of_timefns (void); 97extern void syms_of_timefns (void);
98 98
99INLINE_HEADER_END 99INLINE_HEADER_END
diff --git a/src/textprop.c b/src/textprop.c
index ddcdf26884f..7e29ed6e8b8 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -2319,11 +2319,10 @@ inherits it if NONSTICKINESS is nil. The `front-sticky' and
2319 Vtext_property_default_nonsticky 2319 Vtext_property_default_nonsticky
2320 = list2 (Fcons (Qsyntax_table, Qt), Fcons (Qdisplay, Qt)); 2320 = list2 (Fcons (Qsyntax_table, Qt), Fcons (Qdisplay, Qt));
2321 2321
2322 staticpro (&interval_insert_behind_hooks);
2323 staticpro (&interval_insert_in_front_hooks);
2324 interval_insert_behind_hooks = Qnil; 2322 interval_insert_behind_hooks = Qnil;
2325 interval_insert_in_front_hooks = Qnil; 2323 interval_insert_in_front_hooks = Qnil;
2326 2324 staticpro (&interval_insert_behind_hooks);
2325 staticpro (&interval_insert_in_front_hooks);
2327 2326
2328 /* Common attributes one might give text. */ 2327 /* Common attributes one might give text. */
2329 2328
diff --git a/src/thread.c b/src/thread.c
index ec06493b9e4..33d113295ba 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -25,6 +25,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
25#include "process.h" 25#include "process.h"
26#include "coding.h" 26#include "coding.h"
27#include "syssignal.h" 27#include "syssignal.h"
28#include "pdumper.h"
28#include "keyboard.h" 29#include "keyboard.h"
29 30
30union aligned_thread_state 31union aligned_thread_state
@@ -1064,7 +1065,7 @@ init_main_thread (void)
1064} 1065}
1065 1066
1066bool 1067bool
1067main_thread_p (void *ptr) 1068main_thread_p (const void *ptr)
1068{ 1069{
1069 return ptr == &main_thread.s; 1070 return ptr == &main_thread.s;
1070} 1071}
diff --git a/src/thread.h b/src/thread.h
index 288b671257d..5e003761e85 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -295,7 +295,7 @@ extern void maybe_reacquire_global_lock (void);
295extern void init_threads_once (void); 295extern void init_threads_once (void);
296extern void init_threads (void); 296extern void init_threads (void);
297extern void syms_of_threads (void); 297extern void syms_of_threads (void);
298extern bool main_thread_p (void *); 298extern bool main_thread_p (const void *);
299extern bool in_current_thread (void); 299extern bool in_current_thread (void);
300 300
301typedef int select_func (int, fd_set *, fd_set *, fd_set *, 301typedef int select_func (int, fd_set *, fd_set *, fd_set *,
diff --git a/src/timefns.c b/src/timefns.c
index 4c99fe58061..ce1f4d3f5a9 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -25,6 +25,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
25#include "bignum.h" 25#include "bignum.h"
26#include "coding.h" 26#include "coding.h"
27#include "lisp.h" 27#include "lisp.h"
28#include "pdumper.h"
28 29
29#include <strftime.h> 30#include <strftime.h>
30 31
@@ -291,7 +292,7 @@ tzlookup (Lisp_Object zone, bool settz)
291} 292}
292 293
293void 294void
294init_timefns (bool dumping) 295init_timefns (void)
295{ 296{
296#ifndef CANNOT_DUMP 297#ifndef CANNOT_DUMP
297 /* A valid but unlikely setting for the TZ environment variable. 298 /* A valid but unlikely setting for the TZ environment variable.
@@ -300,7 +301,7 @@ init_timefns (bool dumping)
300 301
301 /* When just dumping out, set the time zone to a known unlikely value 302 /* When just dumping out, set the time zone to a known unlikely value
302 and skip the rest of this function. */ 303 and skip the rest of this function. */
303 if (dumping) 304 if (will_dump_with_unexec_p ())
304 { 305 {
305 xputenv (dump_tz_string); 306 xputenv (dump_tz_string);
306 tzset (); 307 tzset ();
@@ -1729,6 +1730,19 @@ emacs_setenv_TZ (const char *tzstring)
1729 return 0; 1730 return 0;
1730} 1731}
1731 1732
1733#if (ULONG_MAX < TRILLION || !FASTER_TIMEFNS) && !defined ztrillion
1734# define NEED_ZTRILLION_INIT 1
1735#endif
1736
1737#ifdef NEED_ZTRILLION_INIT
1738static void
1739syms_of_timefns_for_pdumper (void)
1740{
1741 mpz_init_set_ui (ztrillion, 1000000);
1742 mpz_mul_ui (ztrillion, ztrillion, 1000000);
1743}
1744#endif
1745
1732void 1746void
1733syms_of_timefns (void) 1747syms_of_timefns (void)
1734{ 1748{
@@ -1740,10 +1754,6 @@ syms_of_timefns (void)
1740 trillion = make_int (1000000000000); 1754 trillion = make_int (1000000000000);
1741 staticpro (&trillion); 1755 staticpro (&trillion);
1742#endif 1756#endif
1743#if (ULONG_MAX < TRILLION || !FASTER_TIMEFNS) && !defined ztrillion
1744 mpz_init_set_ui (ztrillion, 1000000);
1745 mpz_mul_ui (ztrillion, ztrillion, 1000000);
1746#endif
1747 1757
1748 DEFSYM (Qencode_time, "encode-time"); 1758 DEFSYM (Qencode_time, "encode-time");
1749 1759
@@ -1759,4 +1769,7 @@ syms_of_timefns (void)
1759 defsubr (&Scurrent_time_string); 1769 defsubr (&Scurrent_time_string);
1760 defsubr (&Scurrent_time_zone); 1770 defsubr (&Scurrent_time_zone);
1761 defsubr (&Sset_time_zone_rule); 1771 defsubr (&Sset_time_zone_rule);
1772#ifdef NEED_ZTRILLION_INIT
1773 pdumper_do_now_and_after_load (syms_of_timefns_for_pdumper);
1774#endif
1762} 1775}
diff --git a/src/unexw32.c b/src/unexw32.c
index f8941344fcc..6fa0fa055a6 100644
--- a/src/unexw32.c
+++ b/src/unexw32.c
@@ -39,8 +39,6 @@ PIMAGE_NT_HEADERS (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
39 LPDWORD HeaderSum, 39 LPDWORD HeaderSum,
40 LPDWORD CheckSum); 40 LPDWORD CheckSum);
41 41
42extern BOOL ctrl_c_handler (unsigned long type);
43
44extern char my_begdata[]; 42extern char my_begdata[];
45extern char my_begbss[]; 43extern char my_begbss[];
46extern char *my_begbss_static; 44extern char *my_begbss_static;
@@ -70,84 +68,10 @@ PCHAR bss_start_static = 0;
70DWORD_PTR bss_size_static = 0; 68DWORD_PTR bss_size_static = 0;
71DWORD_PTR extra_bss_size_static = 0; 69DWORD_PTR extra_bss_size_static = 0;
72 70
73/* MinGW64 doesn't add a leading underscore to external symbols,
74 whereas configure.ac sets up LD_SWITCH_SYSTEM_TEMACS to force the
75 entry point at __start, with two underscores. */
76#ifdef __MINGW64__
77#define _start __start
78#endif
79
80extern void mainCRTStartup (void);
81
82/* Startup code for running on NT. When we are running as the dumped
83 version, we need to bootstrap our heap and .bss section into our
84 address space before we can actually hand off control to the startup
85 code supplied by NT (primarily because that code relies upon malloc ()). */
86void _start (void);
87
88void
89_start (void)
90{
91
92#if 1
93 /* Give us a way to debug problems with crashes on startup when
94 running under the MSVC profiler. */
95 if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
96 DebugBreak ();
97#endif
98
99 /* Cache system info, e.g., the NT page size. */
100 cache_system_info ();
101
102 /* Grab our malloc arena space now, before CRT starts up. */
103 init_heap ();
104
105 /* This prevents ctrl-c's in shells running while we're suspended from
106 having us exit. */
107 SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
108
109 /* Prevent Emacs from being locked up (eg. in batch mode) when
110 accessing devices that aren't mounted (eg. removable media drives). */
111 SetErrorMode (SEM_FAILCRITICALERRORS);
112 mainCRTStartup ();
113}
114
115
116/* File handling. */ 71/* File handling. */
117 72
118/* Implementation note: this and the next functions work with ANSI 73/* Implementation note: this and the next functions work with ANSI
119 codepage encoded file names! */ 74 codepage encoded file names! */
120int
121open_input_file (file_data *p_file, char *filename)
122{
123 HANDLE file;
124 HANDLE file_mapping;
125 void *file_base;
126 unsigned long size, upper_size;
127
128 file = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
129 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
130 if (file == INVALID_HANDLE_VALUE)
131 return FALSE;
132
133 size = GetFileSize (file, &upper_size);
134 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
135 0, size, NULL);
136 if (!file_mapping)
137 return FALSE;
138
139 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
140 if (file_base == 0)
141 return FALSE;
142
143 p_file->name = filename;
144 p_file->size = size;
145 p_file->file = file;
146 p_file->file_mapping = file_mapping;
147 p_file->file_base = file_base;
148
149 return TRUE;
150}
151 75
152int 76int
153open_output_file (file_data *p_file, char *filename, unsigned long size) 77open_output_file (file_data *p_file, char *filename, unsigned long size)
@@ -187,18 +111,6 @@ open_output_file (file_data *p_file, char *filename, unsigned long size)
187 return TRUE; 111 return TRUE;
188} 112}
189 113
190/* Close the system structures associated with the given file. */
191void
192close_file_data (file_data *p_file)
193{
194 UnmapViewOfFile (p_file->file_base);
195 CloseHandle (p_file->file_mapping);
196 /* For the case of output files, set final size. */
197 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
198 SetEndOfFile (p_file->file);
199 CloseHandle (p_file->file);
200}
201
202 114
203/* Routines to manipulate NT executable file sections. */ 115/* Routines to manipulate NT executable file sections. */
204 116
@@ -220,34 +132,6 @@ find_section (const char * name, IMAGE_NT_HEADERS * nt_header)
220 return NULL; 132 return NULL;
221} 133}
222 134
223/* Return pointer to section header for section containing the given
224 relative virtual address. */
225IMAGE_SECTION_HEADER *
226rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header)
227{
228 PIMAGE_SECTION_HEADER section;
229 int i;
230
231 section = IMAGE_FIRST_SECTION (nt_header);
232
233 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
234 {
235 /* Some linkers (eg. the NT SDK linker I believe) swapped the
236 meaning of these two values - or rather, they ignored
237 VirtualSize entirely and always set it to zero. This affects
238 some very old exes (eg. gzip dated Dec 1993). Since
239 w32_executable_type relies on this function to work reliably,
240 we need to cope with this. */
241 DWORD_PTR real_size = max (section->SizeOfRawData,
242 section->Misc.VirtualSize);
243 if (rva >= section->VirtualAddress
244 && rva < section->VirtualAddress + real_size)
245 return section;
246 section++;
247 }
248 return NULL;
249}
250
251#if 0 /* unused */ 135#if 0 /* unused */
252/* Return pointer to section header for section containing the given 136/* Return pointer to section header for section containing the given
253 offset in its raw data area. */ 137 offset in its raw data area. */
diff --git a/src/w32.c b/src/w32.c
index d141dbd20bb..c75a4f918d3 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -9926,6 +9926,40 @@ maybe_load_unicows_dll (void)
9926 } 9926 }
9927} 9927}
9928 9928
9929/* Relocate a directory specified by epaths.h, using the location of
9930 our binary as an anchor. Note: this runs early during startup, so
9931 we cannot rely on the usual file-related facilities, and in
9932 particular the argument is assumed to be a unibyte string in system
9933 codepage encoding. */
9934const char *
9935w32_relocate (const char *epath_dir)
9936{
9937 if (strncmp (epath_dir, "%emacs_dir%/", 12) == 0)
9938 {
9939 static char relocated_dir[MAX_PATH];
9940
9941 /* Replace "%emacs_dir%" with the parent of the directory where
9942 our binary lives. Note that init_environment was not yet
9943 called, so we cannot rely on emacs_dir being set in the
9944 environment. */
9945 if (GetModuleFileNameA (NULL, relocated_dir, MAX_PATH))
9946 {
9947 char *p = _mbsrchr (relocated_dir, '\\');
9948
9949 if (p)
9950 {
9951 *p = '\0';
9952 if ((p = _mbsrchr (relocated_dir, '\\')) != NULL)
9953 {
9954 strcpy (p, epath_dir + 11);
9955 epath_dir = relocated_dir;
9956 }
9957 }
9958 }
9959 }
9960 return epath_dir;
9961}
9962
9929/* 9963/*
9930 globals_of_w32 is used to initialize those global variables that 9964 globals_of_w32 is used to initialize those global variables that
9931 must always be initialized on startup even when the global variable 9965 must always be initialized on startup even when the global variable
diff --git a/src/w32.h b/src/w32.h
index 6faa90d3177..3790583bfc8 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -185,6 +185,8 @@ extern MultiByteToWideChar_Proc pMultiByteToWideChar;
185extern WideCharToMultiByte_Proc pWideCharToMultiByte; 185extern WideCharToMultiByte_Proc pWideCharToMultiByte;
186extern DWORD multiByteToWideCharFlags; 186extern DWORD multiByteToWideCharFlags;
187 187
188extern const char *w32_relocate (const char *);
189
188extern void init_environment (char **); 190extern void init_environment (char **);
189extern void check_windows_init_file (void); 191extern void check_windows_init_file (void);
190extern void syms_of_ntproc (void); 192extern void syms_of_ntproc (void);
diff --git a/src/w32fns.c b/src/w32fns.c
index 2c239dc7b49..29d85c4826c 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -56,6 +56,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
56#include "w32.h" 56#include "w32.h"
57#endif 57#endif
58 58
59#include "pdumper.h"
60
59#include <basetyps.h> 61#include <basetyps.h>
60#include <unknwn.h> 62#include <unknwn.h>
61#include <commctrl.h> 63#include <commctrl.h>
@@ -10209,6 +10211,7 @@ syms_of_w32fns (void)
10209 track_mouse_window = NULL; 10211 track_mouse_window = NULL;
10210 10212
10211 w32_visible_system_caret_hwnd = NULL; 10213 w32_visible_system_caret_hwnd = NULL;
10214 PDUMPER_IGNORE (w32_visible_system_caret_hwnd);
10212 10215
10213 DEFSYM (Qundefined_color, "undefined-color"); 10216 DEFSYM (Qundefined_color, "undefined-color");
10214 DEFSYM (Qcancel_timer, "cancel-timer"); 10217 DEFSYM (Qcancel_timer, "cancel-timer");
diff --git a/src/w32font.c b/src/w32font.c
index 84d5a876774..33c89825e94 100644
--- a/src/w32font.c
+++ b/src/w32font.c
@@ -33,6 +33,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
33#include "w32.h" 33#include "w32.h"
34#endif 34#endif
35 35
36#include "pdumper.h"
37
36/* Cleartype available on Windows XP, cleartype_natural from XP SP1. 38/* Cleartype available on Windows XP, cleartype_natural from XP SP1.
37 The latter does not try to fit cleartype smoothed fonts into the 39 The latter does not try to fit cleartype smoothed fonts into the
38 same bounding box as the non-antialiased version of the font. 40 same bounding box as the non-antialiased version of the font.
@@ -2624,6 +2626,9 @@ struct font_driver w32font_driver =
2624 2626
2625/* Initialize state that does not change between invocations. This is only 2627/* Initialize state that does not change between invocations. This is only
2626 called when Emacs is dumped. */ 2628 called when Emacs is dumped. */
2629
2630static void syms_of_w32font_for_pdumper (void);
2631
2627void 2632void
2628syms_of_w32font (void) 2633syms_of_w32font (void)
2629{ 2634{
@@ -2803,6 +2808,12 @@ versions of Windows) characters. */);
2803 2808
2804 defsubr (&Sx_select_font); 2809 defsubr (&Sx_select_font);
2805 2810
2811 pdumper_do_now_and_after_load (syms_of_w32font_for_pdumper);
2812}
2813
2814static void
2815syms_of_w32font_for_pdumper (void)
2816{
2806 register_font_driver (&w32font_driver, NULL); 2817 register_font_driver (&w32font_driver, NULL);
2807} 2818}
2808 2819
diff --git a/src/w32heap.c b/src/w32heap.c
index d96e4e2823a..3de8f245ccc 100644
--- a/src/w32heap.c
+++ b/src/w32heap.c
@@ -223,9 +223,16 @@ typedef enum _HEAP_INFORMATION_CLASS {
223typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T); 223typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T);
224#endif 224#endif
225 225
226#ifdef HAVE_PDUMPER
227BOOL using_dynamic_heap = FALSE;
228#endif
229
226void 230void
227init_heap (void) 231init_heap (void)
228{ 232{
233#ifdef HAVE_PDUMPER
234 using_dynamic_heap = TRUE;
235#endif
229 if (using_dynamic_heap) 236 if (using_dynamic_heap)
230 { 237 {
231#ifndef MINGW_W64 238#ifndef MINGW_W64
diff --git a/src/w32menu.c b/src/w32menu.c
index 7d91005f22d..38e1b506e09 100644
--- a/src/w32menu.c
+++ b/src/w32menu.c
@@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
30#include "buffer.h" 30#include "buffer.h"
31#include "coding.h" /* for ENCODE_SYSTEM */ 31#include "coding.h" /* for ENCODE_SYSTEM */
32#include "menu.h" 32#include "menu.h"
33#include "pdumper.h"
33 34
34/* This may include sys/types.h, and that somehow loses 35/* This may include sys/types.h, and that somehow loses
35 if this is not done before the other system files. */ 36 if this is not done before the other system files. */
@@ -1586,6 +1587,7 @@ syms_of_w32menu (void)
1586 globals_of_w32menu (); 1587 globals_of_w32menu ();
1587 1588
1588 current_popup_menu = NULL; 1589 current_popup_menu = NULL;
1590 PDUMPER_IGNORE (current_popup_menu);
1589 1591
1590 DEFSYM (Qdebug_on_next_call, "debug-on-next-call"); 1592 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
1591 DEFSYM (Qunsupported__w32_dialog, "unsupported--w32-dialog"); 1593 DEFSYM (Qunsupported__w32_dialog, "unsupported--w32-dialog");
diff --git a/src/w32proc.c b/src/w32proc.c
index ec60a9cabcc..a5d08f60117 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -81,6 +81,51 @@ static sigset_t sig_mask;
81 81
82static CRITICAL_SECTION crit_sig; 82static CRITICAL_SECTION crit_sig;
83 83
84
85extern BOOL ctrl_c_handler (unsigned long type);
86
87/* MinGW64 doesn't add a leading underscore to external symbols,
88 whereas configure.ac sets up LD_SWITCH_SYSTEM_TEMACS to force the
89 entry point at __start, with two underscores. */
90#ifdef __MINGW64__
91#define _start __start
92#endif
93
94extern void mainCRTStartup (void);
95
96/* Startup code for running on NT. When we are running as the dumped
97 version, we need to bootstrap our heap and .bss section into our
98 address space before we can actually hand off control to the startup
99 code supplied by NT (primarily because that code relies upon malloc ()). */
100void _start (void);
101
102void
103_start (void)
104{
105
106#if 1
107 /* Give us a way to debug problems with crashes on startup when
108 running under the MSVC profiler. */
109 if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
110 DebugBreak ();
111#endif
112
113 /* Cache system info, e.g., the NT page size. */
114 cache_system_info ();
115
116 /* Grab our malloc arena space now, before CRT starts up. */
117 init_heap ();
118
119 /* This prevents ctrl-c's in shells running while we're suspended from
120 having us exit. */
121 SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
122
123 /* Prevent Emacs from being locked up (eg. in batch mode) when
124 accessing devices that aren't mounted (eg. removable media drives). */
125 SetErrorMode (SEM_FAILCRITICALERRORS);
126 mainCRTStartup ();
127}
128
84/* Improve on the CRT 'signal' implementation so that we could record 129/* Improve on the CRT 'signal' implementation so that we could record
85 the SIGCHLD handler and fake interval timers. */ 130 the SIGCHLD handler and fake interval timers. */
86signal_handler 131signal_handler
@@ -1528,6 +1573,78 @@ waitpid (pid_t pid, int *status, int options)
1528 return pid; 1573 return pid;
1529} 1574}
1530 1575
1576int
1577open_input_file (file_data *p_file, char *filename)
1578{
1579 HANDLE file;
1580 HANDLE file_mapping;
1581 void *file_base;
1582 unsigned long size, upper_size;
1583
1584 file = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
1585 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1586 if (file == INVALID_HANDLE_VALUE)
1587 return FALSE;
1588
1589 size = GetFileSize (file, &upper_size);
1590 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
1591 0, size, NULL);
1592 if (!file_mapping)
1593 return FALSE;
1594
1595 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
1596 if (file_base == 0)
1597 return FALSE;
1598
1599 p_file->name = filename;
1600 p_file->size = size;
1601 p_file->file = file;
1602 p_file->file_mapping = file_mapping;
1603 p_file->file_base = file_base;
1604
1605 return TRUE;
1606}
1607
1608/* Return pointer to section header for section containing the given
1609 relative virtual address. */
1610IMAGE_SECTION_HEADER *
1611rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header)
1612{
1613 PIMAGE_SECTION_HEADER section;
1614 int i;
1615
1616 section = IMAGE_FIRST_SECTION (nt_header);
1617
1618 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
1619 {
1620 /* Some linkers (eg. the NT SDK linker I believe) swapped the
1621 meaning of these two values - or rather, they ignored
1622 VirtualSize entirely and always set it to zero. This affects
1623 some very old exes (eg. gzip dated Dec 1993). Since
1624 w32_executable_type relies on this function to work reliably,
1625 we need to cope with this. */
1626 DWORD_PTR real_size = max (section->SizeOfRawData,
1627 section->Misc.VirtualSize);
1628 if (rva >= section->VirtualAddress
1629 && rva < section->VirtualAddress + real_size)
1630 return section;
1631 section++;
1632 }
1633 return NULL;
1634}
1635
1636/* Close the system structures associated with the given file. */
1637void
1638close_file_data (file_data *p_file)
1639{
1640 UnmapViewOfFile (p_file->file_base);
1641 CloseHandle (p_file->file_mapping);
1642 /* For the case of output files, set final size. */
1643 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
1644 SetEndOfFile (p_file->file);
1645 CloseHandle (p_file->file);
1646}
1647
1531/* Old versions of w32api headers don't have separate 32-bit and 1648/* Old versions of w32api headers don't have separate 32-bit and
1532 64-bit defines, but the one they have matches the 32-bit variety. */ 1649 64-bit defines, but the one they have matches the 32-bit variety. */
1533#ifndef IMAGE_NT_OPTIONAL_HDR32_MAGIC 1650#ifndef IMAGE_NT_OPTIONAL_HDR32_MAGIC
diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c
index bec988041ad..c214784fc83 100644
--- a/src/w32uniscribe.c
+++ b/src/w32uniscribe.c
@@ -36,6 +36,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
36#include "composite.h" 36#include "composite.h"
37#include "font.h" 37#include "font.h"
38#include "w32font.h" 38#include "w32font.h"
39#include "pdumper.h"
39#include "w32common.h" 40#include "w32common.h"
40 41
41struct uniscribe_font_info 42struct uniscribe_font_info
@@ -1176,9 +1177,17 @@ struct font_driver uniscribe_font_driver =
1176 as it needs to test for the existence of the Uniscribe library. */ 1177 as it needs to test for the existence of the Uniscribe library. */
1177void syms_of_w32uniscribe (void); 1178void syms_of_w32uniscribe (void);
1178 1179
1180static void syms_of_w32uniscribe_for_pdumper (void);
1181
1179void 1182void
1180syms_of_w32uniscribe (void) 1183syms_of_w32uniscribe (void)
1181{ 1184{
1185 pdumper_do_now_and_after_load (syms_of_w32uniscribe_for_pdumper);
1186}
1187
1188static void
1189syms_of_w32uniscribe_for_pdumper (void)
1190{
1182 HMODULE uniscribe; 1191 HMODULE uniscribe;
1183 1192
1184 /* Don't init uniscribe when dumping */ 1193 /* Don't init uniscribe when dumping */
diff --git a/src/window.c b/src/window.c
index 0fc4f622995..7eb532f78cf 100644
--- a/src/window.c
+++ b/src/window.c
@@ -42,6 +42,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
42#ifdef MSDOS 42#ifdef MSDOS
43#include "msdos.h" 43#include "msdos.h"
44#endif 44#endif
45#include "pdumper.h"
45 46
46static ptrdiff_t count_windows (struct window *); 47static ptrdiff_t count_windows (struct window *);
47static ptrdiff_t get_leaf_windows (struct window *, struct window **, 48static ptrdiff_t get_leaf_windows (struct window *, struct window **,
@@ -7876,10 +7877,59 @@ and scrolling positions. */)
7876 return Qnil; 7877 return Qnil;
7877} 7878}
7878 7879
7880
7881static void init_window_once_for_pdumper (void);
7882
7879void 7883void
7880init_window_once (void) 7884init_window_once (void)
7881{ 7885{
7886 minibuf_window = Qnil;
7887 staticpro (&minibuf_window);
7888
7889 selected_window = Qnil;
7890 staticpro (&selected_window);
7891
7892 Vwindow_list = Qnil;
7893 staticpro (&Vwindow_list);
7894
7895 minibuf_selected_window = Qnil;
7896 staticpro (&minibuf_selected_window);
7897
7898 pdumper_do_now_and_after_load (init_window_once_for_pdumper);
7899}
7900
7901static void init_window_once_for_pdumper (void)
7902{
7903 window_scroll_pixel_based_preserve_x = -1;
7904 window_scroll_pixel_based_preserve_y = -1;
7905 window_scroll_preserve_hpos = -1;
7906 window_scroll_preserve_vpos = -1;
7907 PDUMPER_IGNORE (sequence_number);
7908
7909 PDUMPER_RESET_LV (minibuf_window, Qnil);
7910 PDUMPER_RESET_LV (selected_window, Qnil);
7911 PDUMPER_RESET_LV (Vwindow_list, Qnil);
7912 PDUMPER_RESET_LV (minibuf_selected_window, Qnil);
7913
7914 /* Hack: if mode_line_in_non_selected_windows is true (which it may
7915 be, if we're restoring from a dump) the guts of
7916 make_initial_frame will try to access selected_window, which is
7917 invalid at this point, and lose. For the purposes of creating
7918 the initial frame and window, this variable must be false. */
7919 bool old_mode_line_in_non_selected_windows;
7920
7921 /* Snapshot dumped_with_pdumper to suppress compiler warning. */
7922 bool saved_dumped_with_pdumper = dumped_with_pdumper_p ();
7923 if (saved_dumped_with_pdumper)
7924 {
7925 old_mode_line_in_non_selected_windows
7926 = mode_line_in_non_selected_windows;
7927 mode_line_in_non_selected_windows = false;
7928 }
7882 struct frame *f = make_initial_frame (); 7929 struct frame *f = make_initial_frame ();
7930 if (saved_dumped_with_pdumper)
7931 mode_line_in_non_selected_windows =
7932 old_mode_line_in_non_selected_windows;
7883 XSETFRAME (selected_frame, f); 7933 XSETFRAME (selected_frame, f);
7884 old_selected_frame = Vterminal_frame = selected_frame; 7934 old_selected_frame = Vterminal_frame = selected_frame;
7885 minibuf_window = f->minibuffer_window; 7935 minibuf_window = f->minibuffer_window;
@@ -7932,16 +7982,6 @@ syms_of_window (void)
7932 DEFSYM (Qmode_line_format, "mode-line-format"); 7982 DEFSYM (Qmode_line_format, "mode-line-format");
7933 DEFSYM (Qheader_line_format, "header-line-format"); 7983 DEFSYM (Qheader_line_format, "header-line-format");
7934 7984
7935 staticpro (&Vwindow_list);
7936
7937 minibuf_selected_window = Qnil;
7938 staticpro (&minibuf_selected_window);
7939
7940 window_scroll_pixel_based_preserve_x = -1;
7941 window_scroll_pixel_based_preserve_y = -1;
7942 window_scroll_preserve_hpos = -1;
7943 window_scroll_preserve_vpos = -1;
7944
7945 DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function, 7985 DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function,
7946 doc: /* Non-nil means call as function to display a help buffer. 7986 doc: /* Non-nil means call as function to display a help buffer.
7947The function is called with one argument, the buffer to be displayed. 7987The function is called with one argument, the buffer to be displayed.
diff --git a/src/xfont.c b/src/xfont.c
index b057aa0a277..e40a31004f6 100644
--- a/src/xfont.c
+++ b/src/xfont.c
@@ -31,6 +31,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
31#include "character.h" 31#include "character.h"
32#include "charset.h" 32#include "charset.h"
33#include "font.h" 33#include "font.h"
34#include "pdumper.h"
34 35
35 36
36/* X core font driver. */ 37/* X core font driver. */
@@ -1077,6 +1078,7 @@ xfont_check (struct frame *f, struct font *font)
1077} 1078}
1078 1079
1079 1080
1081static void syms_of_xfont_for_pdumper (void);
1080 1082
1081struct font_driver const xfont_driver = 1083struct font_driver const xfont_driver =
1082 { 1084 {
@@ -1102,5 +1104,11 @@ syms_of_xfont (void)
1102 xfont_scripts_cache = CALLN (Fmake_hash_table, QCtest, Qequal); 1104 xfont_scripts_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
1103 staticpro (&xfont_scratch_props); 1105 staticpro (&xfont_scratch_props);
1104 xfont_scratch_props = make_nil_vector (8); 1106 xfont_scratch_props = make_nil_vector (8);
1107 pdumper_do_now_and_after_load (syms_of_xfont_for_pdumper);
1108}
1109
1110static void
1111syms_of_xfont_for_pdumper (void)
1112{
1105 register_font_driver (&xfont_driver, NULL); 1113 register_font_driver (&xfont_driver, NULL);
1106} 1114}
diff --git a/src/xftfont.c b/src/xftfont.c
index b4f50a2cf8d..ea8572f4242 100644
--- a/src/xftfont.c
+++ b/src/xftfont.c
@@ -32,6 +32,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
32#include "composite.h" 32#include "composite.h"
33#include "font.h" 33#include "font.h"
34#include "ftfont.h" 34#include "ftfont.h"
35#include "pdumper.h"
35 36
36/* Xft font driver. */ 37/* Xft font driver. */
37 38
@@ -751,6 +752,8 @@ xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
751 return ok; 752 return ok;
752} 753}
753 754
755static void syms_of_xftfont_for_pdumper (void);
756
754struct font_driver const xftfont_driver = 757struct font_driver const xftfont_driver =
755 { 758 {
756 /* We can't draw a text without device dependent functions. */ 759 /* We can't draw a text without device dependent functions. */
@@ -802,7 +805,11 @@ syms_of_xftfont (void)
802This is needed with some fonts to correct vertical overlap of glyphs. */); 805This is needed with some fonts to correct vertical overlap of glyphs. */);
803 xft_font_ascent_descent_override = 0; 806 xft_font_ascent_descent_override = 0;
804 807
805 ascii_printable[0] = 0; 808 pdumper_do_now_and_after_load (syms_of_xftfont_for_pdumper);
809}
806 810
811static void
812syms_of_xftfont_for_pdumper (void)
813{
807 register_font_driver (&xftfont_driver, NULL); 814 register_font_driver (&xftfont_driver, NULL);
808} 815}
diff --git a/src/xmenu.c b/src/xmenu.c
index 96c278d42d0..fd7dea4cf8a 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -45,6 +45,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
45#include "buffer.h" 45#include "buffer.h"
46#include "coding.h" 46#include "coding.h"
47#include "sysselect.h" 47#include "sysselect.h"
48#include "pdumper.h"
48 49
49#ifdef MSDOS 50#ifdef MSDOS
50#include "msdos.h" 51#include "msdos.h"
@@ -2401,15 +2402,12 @@ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_
2401 return (popup_activated ()) ? Qt : Qnil; 2402 return (popup_activated ()) ? Qt : Qnil;
2402} 2403}
2403 2404
2405
2406static void syms_of_xmenu_for_pdumper (void);
2407
2404void 2408void
2405syms_of_xmenu (void) 2409syms_of_xmenu (void)
2406{ 2410{
2407#ifdef USE_X_TOOLKIT
2408 enum { WIDGET_ID_TICK_START = 1 << 16 };
2409 widget_id_tick = WIDGET_ID_TICK_START;
2410 next_menubar_widget_id = 1;
2411#endif
2412
2413 DEFSYM (Qdebug_on_next_call, "debug-on-next-call"); 2411 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2414 defsubr (&Smenu_or_popup_active_p); 2412 defsubr (&Smenu_or_popup_active_p);
2415 2413
@@ -2422,4 +2420,16 @@ syms_of_xmenu (void)
2422 Ffset (intern_c_string ("accelerate-menu"), 2420 Ffset (intern_c_string ("accelerate-menu"),
2423 intern_c_string (Sx_menu_bar_open_internal.s.symbol_name)); 2421 intern_c_string (Sx_menu_bar_open_internal.s.symbol_name));
2424#endif 2422#endif
2423
2424 pdumper_do_now_and_after_load (syms_of_xmenu_for_pdumper);
2425}
2426
2427static void
2428syms_of_xmenu_for_pdumper (void)
2429{
2430#ifdef USE_X_TOOLKIT
2431 enum { WIDGET_ID_TICK_START = 1 << 16 };
2432 widget_id_tick = WIDGET_ID_TICK_START;
2433 next_menubar_widget_id = 1;
2434#endif
2425} 2435}
diff --git a/src/xselect.c b/src/xselect.c
index 4621263c62e..37efd43b955 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -35,6 +35,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
35#include "blockinput.h" 35#include "blockinput.h"
36#include "termhooks.h" 36#include "termhooks.h"
37#include "keyboard.h" 37#include "keyboard.h"
38#include "pdumper.h"
38 39
39#include <X11/Xproto.h> 40#include <X11/Xproto.h>
40 41
@@ -2613,6 +2614,9 @@ x_send_client_event (Lisp_Object display, Lisp_Object dest, Lisp_Object from,
2613} 2614}
2614 2615
2615 2616
2617
2618static void syms_of_xselect_for_pdumper (void);
2619
2616void 2620void
2617syms_of_xselect (void) 2621syms_of_xselect (void)
2618{ 2622{
@@ -2628,17 +2632,9 @@ syms_of_xselect (void)
2628 2632
2629 reading_selection_reply = Fcons (Qnil, Qnil); 2633 reading_selection_reply = Fcons (Qnil, Qnil);
2630 staticpro (&reading_selection_reply); 2634 staticpro (&reading_selection_reply);
2631 reading_selection_window = 0;
2632 reading_which_selection = 0;
2633 2635
2634 property_change_wait_list = 0;
2635 prop_location_identifier = 0;
2636 property_change_reply = Fcons (Qnil, Qnil);
2637 staticpro (&property_change_reply); 2636 staticpro (&property_change_reply);
2638 2637
2639 converted_selections = NULL;
2640 conversion_fail_tag = None;
2641
2642 /* FIXME: Duplicate definition in nsselect.c. */ 2638 /* FIXME: Duplicate definition in nsselect.c. */
2643 DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist, 2639 DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist,
2644 doc: /* An alist associating X Windows selection-types with functions. 2640 doc: /* An alist associating X Windows selection-types with functions.
@@ -2717,4 +2713,18 @@ A value of 0 means wait as long as necessary. This is initialized from the
2717 DEFSYM (Qforeign_selection, "foreign-selection"); 2713 DEFSYM (Qforeign_selection, "foreign-selection");
2718 DEFSYM (Qx_lost_selection_functions, "x-lost-selection-functions"); 2714 DEFSYM (Qx_lost_selection_functions, "x-lost-selection-functions");
2719 DEFSYM (Qx_sent_selection_functions, "x-sent-selection-functions"); 2715 DEFSYM (Qx_sent_selection_functions, "x-sent-selection-functions");
2716
2717 pdumper_do_now_and_after_load (syms_of_xselect_for_pdumper);
2718}
2719
2720static void
2721syms_of_xselect_for_pdumper (void)
2722{
2723 reading_selection_window = 0;
2724 reading_which_selection = 0;
2725 property_change_wait_list = 0;
2726 prop_location_identifier = 0;
2727 property_change_reply = Fcons (Qnil, Qnil);
2728 converted_selections = NULL;
2729 conversion_fail_tag = None;
2720} 2730}
diff --git a/src/xsettings.c b/src/xsettings.c
index 60b86f43a87..0c5e36d9d69 100644
--- a/src/xsettings.c
+++ b/src/xsettings.c
@@ -32,6 +32,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
32#include "keyboard.h" 32#include "keyboard.h"
33#include "blockinput.h" 33#include "blockinput.h"
34#include "termhooks.h" 34#include "termhooks.h"
35#include "pdumper.h"
35 36
36#include <X11/Xproto.h> 37#include <X11/Xproto.h>
37 38
@@ -1023,13 +1024,18 @@ void
1023syms_of_xsettings (void) 1024syms_of_xsettings (void)
1024{ 1025{
1025 current_mono_font = NULL; 1026 current_mono_font = NULL;
1027 PDUMPER_IGNORE (current_mono_font);
1026 current_font = NULL; 1028 current_font = NULL;
1029 PDUMPER_IGNORE (current_font);
1027 first_dpyinfo = NULL; 1030 first_dpyinfo = NULL;
1031 PDUMPER_IGNORE (first_dpyinfo);
1028#ifdef HAVE_GSETTINGS 1032#ifdef HAVE_GSETTINGS
1029 gsettings_client = NULL; 1033 gsettings_client = NULL;
1034 PDUMPER_IGNORE (gsettings_client);
1030#endif 1035#endif
1031#ifdef HAVE_GCONF 1036#ifdef HAVE_GCONF
1032 gconf_client = NULL; 1037 gconf_client = NULL;
1038 PDUMPER_IGNORE (gconf_client);
1033#endif 1039#endif
1034 1040
1035 DEFSYM (Qmonospace_font_name, "monospace-font-name"); 1041 DEFSYM (Qmonospace_font_name, "monospace-font-name");
diff --git a/src/xterm.c b/src/xterm.c
index 632703849f8..d8eb45a00c0 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -74,6 +74,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
74#include "xsettings.h" 74#include "xsettings.h"
75#include "sysselect.h" 75#include "sysselect.h"
76#include "menu.h" 76#include "menu.h"
77#include "pdumper.h"
77 78
78#ifdef USE_X_TOOLKIT 79#ifdef USE_X_TOOLKIT
79#include <X11/Shell.h> 80#include <X11/Shell.h>
@@ -13298,6 +13299,7 @@ void
13298syms_of_xterm (void) 13299syms_of_xterm (void)
13299{ 13300{
13300 x_error_message = NULL; 13301 x_error_message = NULL;
13302 PDUMPER_IGNORE (x_error_message);
13301 13303
13302 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms"); 13304 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
13303 DEFSYM (Qlatin_1, "latin-1"); 13305 DEFSYM (Qlatin_1, "latin-1");