diff options
| author | Daniel Colascione | 2019-01-15 17:36:54 -0500 |
|---|---|---|
| committer | Daniel Colascione | 2019-01-15 17:37:36 -0500 |
| commit | d12e5d003d503025c1c9b0335d6518a6c3bdfae1 (patch) | |
| tree | 41829446caca2d488e723843046c4f5b8931d8f8 /src | |
| parent | 2a3bd6798e9670828f0402079fcc116d6d6b042d (diff) | |
| download | emacs-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')
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. |
| 55 | config_h = config.h $(srcdir)/conf_post.h | 55 | config_h = config.h $(srcdir)/conf_post.h |
| 56 | 56 | ||
| 57 | bootstrap_exe = ../src/bootstrap-emacs$(EXEEXT) | ||
| 58 | |||
| 59 | ## ns-app if HAVE_NS, else empty. | 57 | ## ns-app if HAVE_NS, else empty. |
| 60 | OTHER_FILES = @OTHER_FILES@ | 58 | OTHER_FILES = @OTHER_FILES@ |
| 61 | 59 | ||
| @@ -332,7 +330,7 @@ BUILD_DETAILS = @BUILD_DETAILS@ | |||
| 332 | 330 | ||
| 333 | UNEXEC_OBJ = @UNEXEC_OBJ@ | 331 | UNEXEC_OBJ = @UNEXEC_OBJ@ |
| 334 | 332 | ||
| 335 | CANNOT_DUMP=@CANNOT_DUMP@ | 333 | DUMPING=@DUMPING@ |
| 336 | 334 | ||
| 337 | # 'make' verbosity. | 335 | # 'make' verbosity. |
| 338 | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ | 336 | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ |
| @@ -357,6 +355,15 @@ am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) | |||
| 357 | am__v_at_0 = @ | 355 | am__v_at_0 = @ |
| 358 | am__v_at_1 = | 356 | am__v_at_1 = |
| 359 | 357 | ||
| 358 | bootstrap_exe = ../src/bootstrap-emacs$(EXEEXT) | ||
| 359 | ifeq ($(DUMPING),pdumper) | ||
| 360 | bootstrap_pdmp := bootstrap-emacs.pdmp # Keep in sync with loadup.el | ||
| 361 | pdmp := emacs.pdmp | ||
| 362 | else | ||
| 363 | bootstrap_pdmp := | ||
| 364 | pdmp := | ||
| 365 | endif | ||
| 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. |
| 361 | NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd | 368 | NON_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@ | |||
| 446 | ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj) | 453 | ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj) |
| 447 | 454 | ||
| 448 | # Must be first, before dep inclusion! | 455 | # Must be first, before dep inclusion! |
| 449 | all: emacs$(EXEEXT) $(OTHER_FILES) | 456 | all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES) |
| 450 | .PHONY: all | 457 | .PHONY: all |
| 451 | 458 | ||
| 459 | dmpstruct_headers=$(srcdir)/lisp.h $(srcdir)/buffer.h \ | ||
| 460 | $(srcdir)/intervals.h $(srcdir)/charset.h $(srcdir)/bignum.h | ||
| 461 | pdumper.o: dmpstruct.h | ||
| 462 | dmpstruct.h: $(srcdir)/dmpstruct.awk | ||
| 463 | dmpstruct.h: $(libsrc)/make-fingerprint$(EXEEXT) $(dmpstruct_headers) | ||
| 464 | POSIXLY_CORRECT=1 awk -f $(srcdir)/dmpstruct.awk \ | ||
| 465 | $(dmpstruct_headers) > $@ | ||
| 466 | |||
| 452 | AUTO_DEPEND = @AUTO_DEPEND@ | 467 | AUTO_DEPEND = @AUTO_DEPEND@ |
| 453 | DEPDIR = deps | 468 | DEPDIR = deps |
| 454 | ifeq ($(AUTO_DEPEND),yes) | 469 | ifeq ($(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} | |||
| 542 | emacs$(EXEEXT): temacs$(EXEEXT) \ | 557 | emacs$(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} |
| 545 | ifeq ($(CANNOT_DUMP),yes) | 560 | ifeq ($(DUMPING),unexec) |
| 546 | ln -f temacs$(EXEEXT) $@ | 561 | LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=dump |
| 547 | else | ||
| 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) |
| 566 | else | ||
| 567 | cp -f temacs$(EXEEXT) emacs$(EXEEXT) | ||
| 568 | endif | ||
| 569 | |||
| 570 | ifeq ($(DUMPING),pdumper) | ||
| 571 | $(pdmp): emacs$(EXEEXT) | ||
| 572 | LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump | ||
| 573 | cp -f $@ $(bootstrap_pdmp) | ||
| 553 | endif | 574 | endif |
| 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 | ||
| 626 | EMACS_DEPS_PRE=$(LIBXMENU) $(ALLOBJS) | ||
| 627 | EMACS_DEPS_POST=$(LIBEGNU_ARCHIVE) $(EMACSRES) ${charsets} ${charscript} | ||
| 628 | BUILD_EMACS_PRE=$(AM_V_CCLD)$(CC) $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \ | ||
| 629 | -o $@ $(ALLOBJS) | ||
| 630 | BUILD_EMACS_POST=$(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) | ||
| 631 | |||
| 632 | ## We hash this file to generate the build fingerprint | ||
| 633 | temacs.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 | |||
| 639 | fingerprint.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. |
| 609 | temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) \ | 646 | temacs$(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) |
| 614 | ifneq ($(CANNOT_DUMP),yes) | 649 | ifeq ($(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 |
| 641 | ns-app: emacs$(EXEEXT) | 676 | ns-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 | ||
| 647 | mostlyclean: | 682 | mostlyclean: |
| 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. |
| 741 | VCSWITNESS = | 779 | VCSWITNESS = |
| 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 | |||
| 748 | bootstrap-emacs$(EXEEXT): temacs$(EXEEXT) | 788 | bootstrap-emacs$(EXEEXT): temacs$(EXEEXT) |
| 749 | $(MAKE) -C ../lisp update-subdirs | 789 | $(MAKE) -C ../lisp update-subdirs |
| 750 | ifeq ($(CANNOT_DUMP),yes) | 790 | ifeq ($(DUMPING),unexec) |
| 751 | ln -f temacs$(EXEEXT) $@ | 791 | $(RUN_TEMACS) --batch $(BUILD_DETAILS) -l loadup --temacs=bootstrap |
| 752 | else | ||
| 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)" | ||
| 798 | else | ||
| 799 | @: In the pdumper case, make compile-first after the dump | ||
| 800 | cp -f temacs$(EXEEXT) bootstrap-emacs$(EXEEXT) | ||
| 758 | endif | 801 | endif |
| 802 | |||
| 803 | ifeq ($(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)" |
| 809 | endif | ||
| 761 | 810 | ||
| 762 | ### Flymake support (for C only) | 811 | ### Flymake support (for C only) |
| 763 | check-syntax: | 812 | check-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> |
| 77 | static 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 | ||
| 202 | void | 197 | void |
| @@ -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 | ||
| 243 | byte_ct memory_full_cons_threshold; | 235 | byte_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. */ | ||
| 240 | int number_finalizers_run; | ||
| 241 | #endif | ||
| 242 | |||
| 245 | /* True during GC. */ | 243 | /* True during GC. */ |
| 246 | 244 | ||
| 247 | bool gc_in_progress; | 245 | bool gc_in_progress; |
| @@ -375,6 +373,27 @@ static void compact_small_strings (void); | |||
| 375 | static void free_large_strings (void); | 373 | static void free_large_strings (void); |
| 376 | extern Lisp_Object which_symbols (Lisp_Object, EMACS_INT) EXTERNALLY_VISIBLE; | 374 | extern 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 | |||
| 379 | inline static bool vector_marked_p (const struct Lisp_Vector *v); | ||
| 380 | inline static void set_vector_marked (struct Lisp_Vector *v); | ||
| 381 | |||
| 382 | inline static bool vectorlike_marked_p (const union vectorlike_header *v); | ||
| 383 | inline static void set_vectorlike_marked (union vectorlike_header *v); | ||
| 384 | |||
| 385 | inline static bool cons_marked_p (const struct Lisp_Cons *c); | ||
| 386 | inline static void set_cons_marked (struct Lisp_Cons *c); | ||
| 387 | |||
| 388 | inline static bool string_marked_p (const struct Lisp_String *s); | ||
| 389 | inline static void set_string_marked (struct Lisp_String *s); | ||
| 390 | |||
| 391 | inline static bool symbol_marked_p (const struct Lisp_Symbol *s); | ||
| 392 | inline static void set_symbol_marked (struct Lisp_Symbol *s); | ||
| 393 | |||
| 394 | inline static bool interval_marked_p (INTERVAL i); | ||
| 395 | inline 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 | ||
| 403 | static Lisp_Object Vdead; | 422 | #ifndef ENABLE_CHECKING |
| 423 | static | ||
| 424 | #endif | ||
| 425 | Lisp_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 | ||
| 483 | enum { NSTATICS = 2048 }; | 506 | Lisp_Object *staticvec[NSTATICS] |
| 484 | static 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 | ||
| 488 | static int staticidx; | 514 | int staticidx; |
| 489 | 515 | ||
| 490 | static void *pure_alloc (size_t, int); | 516 | static 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 | ||
| 507 | static void * | 520 | static 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. */ |
| 579 | static struct Lisp_Finalizer finalizers; | 592 | struct 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. */ |
| 585 | static struct Lisp_Finalizer doomed_finalizers; | 598 | struct 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) | |||
| 1153 | static void | 1168 | static void |
| 1154 | lisp_free (void *block) | 1169 | lisp_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 | ||
| 1571 | static void | 1589 | static void |
| 1572 | mark_interval (INTERVAL i, void *dummy) | 1590 | mark_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) \ | 1601 | static void |
| 1584 | do { \ | 1602 | mark_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 | |||
| 1820 | init_strings (void) | 1839 | init_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 | |||
| 3103 | init_vectors (void) | 3126 | init_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 | ||
| 3176 | static ptrdiff_t | 3200 | ptrdiff_t |
| 3177 | vector_nbytes (struct Lisp_Vector *v) | 3201 | vectorlike_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 | |||
| 3885 | run_finalizer_function (Lisp_Object function) | 3910 | run_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 | |||
| 3969 | static bool | ||
| 3970 | vector_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 | |||
| 3986 | static void | ||
| 3987 | set_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 | |||
| 3998 | static bool | ||
| 3999 | vectorlike_marked_p (const union vectorlike_header *header) | ||
| 4000 | { | ||
| 4001 | return vector_marked_p ((const struct Lisp_Vector *) header); | ||
| 4002 | } | ||
| 4003 | |||
| 4004 | static void | ||
| 4005 | set_vectorlike_marked (union vectorlike_header *header) | ||
| 4006 | { | ||
| 4007 | set_vector_marked ((struct Lisp_Vector *) header); | ||
| 4008 | } | ||
| 4009 | |||
| 4010 | static bool | ||
| 4011 | cons_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 | |||
| 4018 | static void | ||
| 4019 | set_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 | |||
| 4027 | static bool | ||
| 4028 | string_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 | |||
| 4035 | static void | ||
| 4036 | set_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 | |||
| 4044 | static bool | ||
| 4045 | symbol_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 | |||
| 4052 | static void | ||
| 4053 | set_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 | |||
| 4061 | static bool | ||
| 4062 | interval_marked_p (INTERVAL i) | ||
| 4063 | { | ||
| 4064 | return pdumper_object_p (i) | ||
| 4065 | ? pdumper_marked_p (i) | ||
| 4066 | : i->gcmarkbit; | ||
| 4067 | } | ||
| 4068 | |||
| 4069 | static void | ||
| 4070 | set_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 | |||
| 4626 | mark_maybe_object (Lisp_Object obj) | 4774 | mark_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 | ||
| 5931 | static void | ||
| 5932 | visit_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 | |||
| 5945 | static void | ||
| 5946 | visit_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. */ | ||
| 5966 | void | ||
| 5967 | visit_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 | |||
| 5986 | static void | ||
| 5987 | mark_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. */ | ||
| 5997 | static struct Lisp_Hash_Table *weak_hash_tables; | ||
| 5998 | |||
| 5999 | NO_INLINE /* For better stack traces */ | ||
| 6000 | static void | ||
| 6001 | mark_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; | |||
| 6060 | ptrdiff_t mark_object_loop_halt EXTERNALLY_VISIBLE; | 6339 | ptrdiff_t mark_object_loop_halt EXTERNALLY_VISIBLE; |
| 6061 | 6340 | ||
| 6062 | static void | 6341 | static void |
| 6063 | mark_vectorlike (struct Lisp_Vector *ptr) | 6342 | mark_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) | |||
| 6125 | static void | 6410 | static void |
| 6126 | mark_overlay (struct Lisp_Overlay *ptr) | 6411 | mark_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 | |||
| 6141 | mark_buffer (struct buffer *buffer) | 6426 | mark_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 | ||
| 6514 | static void | ||
| 6515 | mark_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 | |||
| 6531 | static void | ||
| 6532 | mark_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 | |||
| 6557 | static void | ||
| 6558 | mark_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) | |||
| 6887 | static void | 7218 | static void |
| 6888 | gc_sweep (void) | 7219 | gc_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 | ||
| 7482 | static void init_alloc_once_for_pdumper (void); | ||
| 7483 | |||
| 7154 | void | 7484 | void |
| 7155 | init_alloc_once (void) | 7485 | init_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 | |||
| 7505 | static void | ||
| 7506 | init_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 | ||
| 7182 | void | 7525 | void |
| @@ -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 | ||
| 7193 | void | 7532 | void |
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) | |||
| 5001 | void | 5006 | void |
| 5002 | enlarge_buffer_text (struct buffer *b, ptrdiff_t delta) | 5007 | enlarge_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 | |||
| 5052 | void | 5072 | void |
| 5053 | init_buffer_once (void) | 5073 | init_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 (¤t_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 | ||
| 5268 | void | 5307 | void |
| 5269 | init_buffer (int initialized) | 5308 | init_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. */ | ||
| 53 | static 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. */ |
| 63 | struct charset *charset_table; | 64 | struct charset *charset_table; |
| 64 | 65 | ptrdiff_t charset_table_size; | |
| 65 | static ptrdiff_t charset_table_size; | 66 | int charset_table_used; |
| 66 | static int charset_table_used; | ||
| 67 | 67 | ||
| 68 | /* Special charsets corresponding to symbols. */ | 68 | /* Special charsets corresponding to symbols. */ |
| 69 | int charset_ascii; | 69 | int 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. */ |
| 250 | extern struct charset *charset_table; | 250 | extern struct charset *charset_table; |
| 251 | extern ptrdiff_t charset_table_size; | ||
| 252 | extern 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 | ||
| 302 | Lisp_Object Vcoding_system_hash_table; | 303 | Lisp_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 | ||
| 10769 | void | 10777 | void |
| @@ -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 | |||
| 654 | composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len) | 654 | composition_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 | ||
| 5991 | static void | ||
| 5992 | init_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 | ||
| 5994 | void | 6007 | static void |
| 5995 | init_display (void) | 6008 | init_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; | 6185 | void |
| 6183 | FRAME_BACKGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_BG_COLOR; | 6186 | init_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 | ||
| 6231 | static void syms_of_display_for_pdumper (void); | ||
| 6232 | |||
| 6223 | void | 6233 | void |
| 6224 | syms_of_display (void) | 6234 | syms_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 | { | 6343 | static void |
| 6334 | Vinitial_window_system = Qnil; | 6344 | syms_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 @@ | |||
| 1 | BEGIN { | ||
| 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 | } | ||
| 26 | END { | ||
| 27 | print "#endif /* EMACS_DMPSTRUCT_H */" | ||
| 28 | } | ||
| @@ -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 | |||
| 1191 | syms_of_module (void) | 1191 | syms_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 (<v_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 | |||
| 121 | static const char emacs_version[] = PACKAGE_VERSION; | 124 | static const char emacs_version[] = PACKAGE_VERSION; |
| 122 | static const char emacs_copyright[] = COPYRIGHT; | 125 | static const char emacs_copyright[] = COPYRIGHT; |
| 123 | static const char emacs_bugreport[] = PACKAGE_BUGREPORT; | 126 | static const char emacs_bugreport[] = PACKAGE_BUGREPORT; |
| @@ -130,19 +133,9 @@ Lisp_Object empty_unibyte_string, empty_multibyte_string; | |||
| 130 | Lisp_Object Vlibrary_cache; | 133 | Lisp_Object Vlibrary_cache; |
| 131 | #endif | 134 | #endif |
| 132 | 135 | ||
| 133 | /* Set after Emacs has started up the first time. | 136 | struct gflags gflags; |
| 134 | Prevents reinitialization of the Lisp world and keymaps | ||
| 135 | on subsequent starts. */ | ||
| 136 | bool initialized; | 137 | bool initialized; |
| 137 | 138 | ||
| 138 | #ifndef CANNOT_DUMP | ||
| 139 | /* Set to true if this instance of Emacs might dump. */ | ||
| 140 | # ifndef DOUG_LEA_MALLOC | ||
| 141 | static | ||
| 142 | # endif | ||
| 143 | bool 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. */ |
| 148 | bool inhibit_window_system; | 141 | bool 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 | ||
| 653 | static bool | ||
| 654 | string_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. */ | ||
| 662 | static char * | ||
| 663 | find_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. */ |
| 664 | static void | 692 | static 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 | |||
| 710 | static const char * | ||
| 711 | dump_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 | |||
| 736 | static enum pdumper_load_result | ||
| 737 | load_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 */ |
| 681 | int | 817 | int |
| 682 | main (int argc, char **argv) | 818 | main (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. |
| 2675 | Each element is a list (LIBRARY FILE...), where the car is a symbol | 2875 | Each 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! */ |
| 90 | Lisp_Object Vsignaling_function; | 91 | Lisp_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. */ | ||
| 94 | Lisp_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. */ |
| 97 | bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE; | 94 | bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE; |
| 98 | Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE; | 95 | Lisp_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 | ||
| 235 | static void init_eval_once_for_pdumper (void); | ||
| 236 | |||
| 238 | static union specbinding * | 237 | static union specbinding * |
| 239 | backtrace_thread_next (struct thread_state *tstate, union specbinding *pdl) | 238 | backtrace_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) | |||
| 247 | void | 246 | void |
| 248 | init_eval_once (void) | 247 | init_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 | |||
| 256 | static void | ||
| 257 | init_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 | |||
| 3 | Copyright (C) 2016 Free Software Foundation, | ||
| 4 | Inc. | ||
| 5 | |||
| 6 | This file is part of GNU Emacs. | ||
| 7 | |||
| 8 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 9 | it under the terms of the GNU General Public License as published by | ||
| 10 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 11 | your option) any later version. | ||
| 12 | |||
| 13 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | GNU General Public License for more details. | ||
| 17 | |||
| 18 | You should have received a copy of the GNU General Public License | ||
| 19 | along 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. */ | ||
| 24 | const 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 | |||
| 3 | Copyright (C) 2016 Free Software Foundation, | ||
| 4 | Inc. | ||
| 5 | |||
| 6 | This file is part of GNU Emacs. | ||
| 7 | |||
| 8 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 9 | it under the terms of the GNU General Public License as published by | ||
| 10 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 11 | your option) any later version. | ||
| 12 | |||
| 13 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | GNU General Public License for more details. | ||
| 17 | |||
| 18 | You should have received a copy of the GNU General Public License | ||
| 19 | along 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. */ | ||
| 30 | extern const uint8_t fingerprint[32]; | ||
| 31 | |||
| 32 | #endif | ||
| @@ -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 | |||
| 3653 | static 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 | ||
| 3869 | static EMACS_UINT | 3865 | EMACS_UINT |
| 3870 | hashfn_equal (struct hash_table_test *ht, Lisp_Object key) | 3866 | hashfn_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 | ||
| 3879 | static EMACS_UINT | 3875 | EMACS_UINT |
| 3880 | hashfn_eql (struct hash_table_test *ht, Lisp_Object key) | 3876 | hashfn_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 | ||
| 4101 | void | ||
| 4102 | hash_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 | ||
| 4258 | static bool | 4284 | bool |
| 4259 | sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p) | 4285 | sweep_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 | |||
| 4343 | NO_INLINE /* For better stack traces */ | ||
| 4344 | void | ||
| 4345 | sweep_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 | |||
| 5297 | void | 5278 | void |
| 5298 | syms_of_fns (void) | 5279 | syms_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. */ |
| 58 | Lisp_Object selected_frame; | 59 | Lisp_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 | ||
| 5627 | static void init_frame_once_for_pdumper (void); | ||
| 5628 | |||
| 5629 | void | ||
| 5630 | init_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 | |||
| 5640 | static void | ||
| 5641 | init_frame_once_for_pdumper (void) | ||
| 5642 | { | ||
| 5643 | PDUMPER_RESET_LV (Vframe_list, Qnil); | ||
| 5644 | PDUMPER_RESET_LV (selected_frame, Qnil); | ||
| 5645 | } | ||
| 5646 | |||
| 5629 | void | 5647 | void |
| 5630 | syms_of_frame (void) | 5648 | syms_of_frame (void) |
| 5631 | { | 5649 | { |
| @@ -6107,8 +6125,6 @@ making the child frame unresponsive to user actions, the default is to | |||
| 6107 | iconify the top level frame instead. */); | 6125 | iconify 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 | ||
| 1743 | static void init_fringe_once_for_pdumper (void); | ||
| 1744 | |||
| 1742 | void | 1745 | void |
| 1743 | init_fringe_once (void) | 1746 | init_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++) | 1751 | static void |
| 1752 | init_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 | ||
| 286 | static void syms_of_ftcrfont_for_pdumper (void); | ||
| 287 | |||
| 285 | struct font_driver const ftcrfont_driver = | 288 | struct 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 | |||
| 326 | static void | ||
| 327 | syms_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 | ||
| 38 | static struct font_driver const ftfont_driver; | 39 | static 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 | ||
| 2705 | static void syms_of_ftfont_for_pdumper (void); | ||
| 2706 | |||
| 2704 | static struct font_driver const ftfont_driver = | 2707 | static 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 | |||
| 2761 | static void | ||
| 2762 | syms_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 | ||
| 343 | static void syms_of_ftxfont_for_pdumper (void); | ||
| 344 | |||
| 342 | struct font_driver const ftxfont_driver = | 345 | struct 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 | |||
| 373 | syms_of_ftxfont (void) | 376 | syms_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 | |||
| 382 | static void | ||
| 383 | syms_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 * | |||
| 1508 | gdefault_morecore (ptrdiff_t increment) | 1507 | gdefault_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); | |||
| 1726 | static bool | 1725 | static bool |
| 1727 | allocated_via_gmalloc (void *ptr) | 1726 | allocated_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) | |||
| 1737 | void * | 1738 | void * |
| 1738 | hybrid_malloc (size_t size) | 1739 | hybrid_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) | |||
| 1745 | void * | 1746 | void * |
| 1746 | hybrid_calloc (size_t nmemb, size_t size) | 1747 | hybrid_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) | |||
| 1763 | void * | 1764 | void * |
| 1764 | hybrid_aligned_alloc (size_t alignment, size_t size) | 1765 | hybrid_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 | |||
| 10003 | syms_of_image (void) | 10004 | syms_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 | ||
| 33 | static void insert_from_string_1 (Lisp_Object, ptrdiff_t, ptrdiff_t, ptrdiff_t, | 34 | static 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 | |||
| 29 | struct interval | 29 | struct 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 | ||
| 10982 | static void syms_of_keyboard_for_pdumper (void); | ||
| 10983 | |||
| 10980 | void | 10984 | void |
| 10981 | syms_of_keyboard (void) | 10985 | syms_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 (®ular_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. | |||
| 11828 | If nil, Emacs crashes immediately in response to fatal signals. */); | 11834 | If 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 | |||
| 11840 | static void | ||
| 11841 | syms_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); | |||
| 623 | extern _Noreturn void wrong_type_argument (Lisp_Object, Lisp_Object); | 624 | extern _Noreturn void wrong_type_argument (Lisp_Object, Lisp_Object); |
| 624 | 625 | ||
| 625 | 626 | ||
| 626 | #ifdef CANNOT_DUMP | ||
| 627 | enum { might_dump = false }; | ||
| 628 | #elif defined DOUG_LEA_MALLOC | ||
| 629 | /* Defined in emacs.c. */ | 627 | /* Defined in emacs.c. */ |
| 630 | extern 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. */ |
| 634 | extern bool initialized; | 632 | extern bool initialized; |
| 635 | 633 | ||
| 634 | extern 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 | |||
| 658 | INLINE bool | ||
| 659 | will_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 | |||
| 668 | INLINE bool | ||
| 669 | will_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 | |||
| 678 | INLINE bool | ||
| 679 | will_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 | |||
| 688 | INLINE bool | ||
| 689 | dumped_with_pdumper_p (void) | ||
| 690 | { | ||
| 691 | #if HAVE_PDUMPER | ||
| 692 | return gflags.dumped_with_pdumper_; | ||
| 693 | #else | ||
| 694 | return false; | ||
| 695 | #endif | ||
| 696 | } | ||
| 697 | |||
| 698 | INLINE bool | ||
| 699 | will_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 | |||
| 708 | INLINE bool | ||
| 709 | dumped_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. */ | ||
| 721 | INLINE bool | ||
| 722 | definitely_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. */ |
| 637 | extern double extract_float (Lisp_Object); | 732 | extern 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 | ||
| 1570 | INLINE enum pvec_type | 1678 | INLINE enum pvec_type |
| 1571 | PSEUDOVECTOR_TYPE (struct Lisp_Vector *v) | 1679 | PSEUDOVECTOR_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. */ |
| 1580 | INLINE bool | 1688 | INLINE bool |
| 1581 | PSEUDOVECTOR_TYPEP (union vectorlike_header *a, enum pvec_type code) | 1689 | PSEUDOVECTOR_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 | ||
| 2169 | struct Lisp_Hash_Table | 2277 | struct 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. */ |
| 2252 | INLINE Lisp_Object | 2367 | INLINE Lisp_Object |
| 2253 | HASH_KEY (struct Lisp_Hash_Table *h, ptrdiff_t idx) | 2368 | HASH_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. */ |
| 2259 | INLINE Lisp_Object | 2374 | INLINE Lisp_Object |
| 2260 | HASH_VALUE (struct Lisp_Hash_Table *h, ptrdiff_t idx) | 2375 | HASH_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. */ |
| 2266 | INLINE Lisp_Object | 2381 | INLINE Lisp_Object |
| 2267 | HASH_HASH (struct Lisp_Hash_Table *h, ptrdiff_t idx) | 2382 | HASH_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. */ |
| 2273 | INLINE ptrdiff_t | 2388 | INLINE ptrdiff_t |
| 2274 | HASH_TABLE_SIZE (struct Lisp_Hash_Table *h) | 2389 | HASH_TABLE_SIZE (const struct Lisp_Hash_Table *h) |
| 2275 | { | 2390 | { |
| 2276 | return ASIZE (h->next); | 2391 | return ASIZE (h->next); |
| 2277 | } | 2392 | } |
| 2278 | 2393 | ||
| 2394 | void hash_table_rehash (struct Lisp_Hash_Table *h); | ||
| 2395 | |||
| 2396 | INLINE bool | ||
| 2397 | hash_rehash_needed_p (const struct Lisp_Hash_Table *h) | ||
| 2398 | { | ||
| 2399 | return h->count < 0; | ||
| 2400 | } | ||
| 2401 | |||
| 2402 | INLINE void | ||
| 2403 | hash_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 | ||
| 2281 | enum DEFAULT_HASH_SIZE { DEFAULT_HASH_SIZE = 65 }; | 2411 | enum 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 | ||
| 2574 | extern struct Lisp_Finalizer finalizers; | ||
| 2575 | extern struct Lisp_Finalizer doomed_finalizers; | ||
| 2576 | |||
| 2444 | INLINE bool | 2577 | INLINE bool |
| 2445 | FINALIZERP (Lisp_Object x) | 2578 | FINALIZERP (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 | ||
| 3171 | void staticpro (Lisp_Object *); | 3319 | void staticpro (Lisp_Object *); |
| 3320 | |||
| 3321 | enum { NSTATICS = 2048 }; | ||
| 3322 | extern Lisp_Object *staticvec[NSTATICS]; | ||
| 3323 | extern int staticidx; | ||
| 3324 | |||
| 3172 | 3325 | ||
| 3173 | /* Forward declarations for prototypes. */ | 3326 | /* Forward declarations for prototypes. */ |
| 3174 | struct window; | 3327 | struct window; |
| @@ -3416,12 +3569,14 @@ enum { NEXT_ALMOST_PRIME_LIMIT = 11 }; | |||
| 3416 | extern ptrdiff_t list_length (Lisp_Object); | 3569 | extern ptrdiff_t list_length (Lisp_Object); |
| 3417 | extern EMACS_INT next_almost_prime (EMACS_INT) ATTRIBUTE_CONST; | 3570 | extern EMACS_INT next_almost_prime (EMACS_INT) ATTRIBUTE_CONST; |
| 3418 | extern Lisp_Object larger_vector (Lisp_Object, ptrdiff_t, ptrdiff_t); | 3571 | extern Lisp_Object larger_vector (Lisp_Object, ptrdiff_t, ptrdiff_t); |
| 3419 | extern void sweep_weak_hash_tables (void); | 3572 | extern bool sweep_weak_table (struct Lisp_Hash_Table *, bool); |
| 3420 | extern char *extract_data_from_object (Lisp_Object, ptrdiff_t *, ptrdiff_t *); | 3573 | extern char *extract_data_from_object (Lisp_Object, ptrdiff_t *, ptrdiff_t *); |
| 3421 | EMACS_UINT hash_string (char const *, ptrdiff_t); | 3574 | EMACS_UINT hash_string (char const *, ptrdiff_t); |
| 3422 | EMACS_UINT sxhash (Lisp_Object, int); | 3575 | EMACS_UINT sxhash (Lisp_Object, int); |
| 3576 | EMACS_UINT hashfn_eql (struct hash_table_test *ht, Lisp_Object key); | ||
| 3577 | EMACS_UINT hashfn_equal (struct hash_table_test *ht, Lisp_Object key); | ||
| 3423 | Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float, | 3578 | Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float, |
| 3424 | Lisp_Object, bool); | 3579 | Lisp_Object, bool); |
| 3425 | ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, EMACS_UINT *); | 3580 | ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, EMACS_UINT *); |
| 3426 | ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object, | 3581 | ptrdiff_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. */ | |||
| 3592 | extern byte_ct consing_since_gc; | 3747 | extern byte_ct consing_since_gc; |
| 3593 | extern byte_ct gc_relative_threshold; | 3748 | extern byte_ct gc_relative_threshold; |
| 3594 | extern byte_ct memory_full_cons_threshold; | 3749 | extern byte_ct memory_full_cons_threshold; |
| 3750 | #ifdef HAVE_PDUMPER | ||
| 3751 | extern int number_finalizers_run; | ||
| 3752 | #endif | ||
| 3753 | #ifdef ENABLE_CHECKING | ||
| 3754 | extern Lisp_Object Vdead; | ||
| 3755 | #endif | ||
| 3595 | extern Lisp_Object list1 (Lisp_Object); | 3756 | extern Lisp_Object list1 (Lisp_Object); |
| 3596 | extern Lisp_Object list2 (Lisp_Object, Lisp_Object); | 3757 | extern Lisp_Object list2 (Lisp_Object, Lisp_Object); |
| 3597 | extern Lisp_Object list3 (Lisp_Object, Lisp_Object, Lisp_Object); | 3758 | extern 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, | |||
| 3601 | enum constype {CONSTYPE_HEAP, CONSTYPE_PURE}; | 3762 | enum constype {CONSTYPE_HEAP, CONSTYPE_PURE}; |
| 3602 | extern Lisp_Object listn (enum constype, ptrdiff_t, Lisp_Object, ...); | 3763 | extern Lisp_Object listn (enum constype, ptrdiff_t, Lisp_Object, ...); |
| 3603 | 3764 | ||
| 3765 | enum 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 | |||
| 3772 | struct gc_root_visitor { | ||
| 3773 | void (*visit)(Lisp_Object *root_ptr, | ||
| 3774 | enum gc_root_type type, | ||
| 3775 | void *data); | ||
| 3776 | void *data; | ||
| 3777 | }; | ||
| 3778 | extern 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 | ||
| 3606 | INLINE Lisp_Object | 3782 | INLINE Lisp_Object |
| @@ -3629,6 +3805,13 @@ extern Lisp_Object make_string (const char *, ptrdiff_t); | |||
| 3629 | extern Lisp_Object make_formatted_string (char *, const char *, ...) | 3805 | extern Lisp_Object make_formatted_string (char *, const char *, ...) |
| 3630 | ATTRIBUTE_FORMAT_PRINTF (2, 3); | 3806 | ATTRIBUTE_FORMAT_PRINTF (2, 3); |
| 3631 | extern Lisp_Object make_unibyte_string (const char *, ptrdiff_t); | 3807 | extern Lisp_Object make_unibyte_string (const char *, ptrdiff_t); |
| 3808 | extern ptrdiff_t vectorlike_nbytes (const union vectorlike_header *hdr); | ||
| 3809 | |||
| 3810 | INLINE ptrdiff_t | ||
| 3811 | vector_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 *); | |||
| 3824 | extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), | 4007 | extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), |
| 3825 | Lisp_Object); | 4008 | Lisp_Object); |
| 3826 | extern void dir_warning (const char *, Lisp_Object); | 4009 | extern void dir_warning (const char *, Lisp_Object); |
| 3827 | extern void init_obarray (void); | 4010 | extern void init_obarray_once (void); |
| 3828 | extern void init_lread (void); | 4011 | extern void init_lread (void); |
| 3829 | extern void syms_of_lread (void); | 4012 | extern 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. */ |
| 4175 | extern struct thread_state primary_thread; | ||
| 3992 | extern void mark_threads (void); | 4176 | extern void mark_threads (void); |
| 3993 | extern void unmark_main_thread (void); | 4177 | extern void unmark_main_thread (void); |
| 3994 | 4178 | ||
| @@ -4017,7 +4201,7 @@ extern bool overlay_touches_p (ptrdiff_t); | |||
| 4017 | extern Lisp_Object other_buffer_safely (Lisp_Object); | 4201 | extern Lisp_Object other_buffer_safely (Lisp_Object); |
| 4018 | extern Lisp_Object get_truename_buffer (Lisp_Object); | 4202 | extern Lisp_Object get_truename_buffer (Lisp_Object); |
| 4019 | extern void init_buffer_once (void); | 4203 | extern void init_buffer_once (void); |
| 4020 | extern void init_buffer (int); | 4204 | extern void init_buffer (void); |
| 4021 | extern void syms_of_buffer (void); | 4205 | extern void syms_of_buffer (void); |
| 4022 | extern void keys_of_buffer (void); | 4206 | extern void keys_of_buffer (void); |
| 4023 | 4207 | ||
| @@ -4160,6 +4344,7 @@ extern void store_in_alist (Lisp_Object *, Lisp_Object, Lisp_Object); | |||
| 4160 | extern Lisp_Object do_switch_frame (Lisp_Object, int, int, Lisp_Object); | 4344 | extern Lisp_Object do_switch_frame (Lisp_Object, int, int, Lisp_Object); |
| 4161 | extern Lisp_Object get_frame_param (struct frame *, Lisp_Object); | 4345 | extern Lisp_Object get_frame_param (struct frame *, Lisp_Object); |
| 4162 | extern void frames_discard_buffer (Lisp_Object); | 4346 | extern void frames_discard_buffer (Lisp_Object); |
| 4347 | extern void init_frame_once (void); | ||
| 4163 | extern void syms_of_frame (void); | 4348 | extern 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 | ||
| 4375 | void | 4376 | void |
| 4376 | init_obarray (void) | 4377 | init_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 | ||
| 4405 | int ndefsubr; | ||
| 4406 | |||
| 4403 | void | 4407 | void |
| 4404 | defsubr (union Aligned_Lisp_Subr *aname) | 4408 | defsubr (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) | |||
| 4553 | static Lisp_Object | 4556 | static Lisp_Object |
| 4554 | load_path_default (void) | 4557 | load_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, | |||
| 1029 | static void | 1030 | static void |
| 1030 | macfont_init_font_change_handler (void) | 1031 | macfont_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]); |
| 1647 | static void macfont_filter_properties (Lisp_Object, Lisp_Object); | 1648 | static void macfont_filter_properties (Lisp_Object, Lisp_Object); |
| 1648 | 1649 | ||
| 1649 | static struct font_driver const macfont_driver = | 1650 | static 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 | |||
| 4033 | static void syms_of_macfont_for_pdumper (void); | ||
| 4034 | |||
| 4031 | void | 4035 | void |
| 4032 | syms_of_macfont (void) | 4036 | syms_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 | |||
| 4058 | static void | ||
| 4059 | syms_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 | |||
| 1576 | void | 1576 | void |
| 1577 | syms_of_menu (void) | 1577 | syms_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 | |||
| 1866 | static void init_minibuf_once_for_pdumper (void); | ||
| 1867 | |||
| 1861 | void | 1868 | void |
| 1862 | init_minibuf_once (void) | 1869 | init_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 | ||
| 1868 | void | 1875 | static void |
| 1869 | syms_of_minibuf (void) | 1876 | init_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 | |||
| 1891 | void | ||
| 1892 | syms_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 | ||
| 55 | static EmacsTooltip *ns_tooltip = nil; | 54 | static EmacsTooltip *ns_tooltip = nil; |
| @@ -3125,7 +3124,6 @@ handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent) | |||
| 3125 | 3124 | ||
| 3126 | ========================================================================== */ | 3125 | ========================================================================== */ |
| 3127 | 3126 | ||
| 3128 | |||
| 3129 | void | 3127 | void |
| 3130 | syms_of_nsfns (void) | 3128 | syms_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 | ||
| 1487 | static void syms_of_nsfont_for_pdumper (void); | ||
| 1488 | |||
| 1486 | struct font_driver const nsfont_driver = | 1489 | struct 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 = | |||
| 1502 | void | 1505 | void |
| 1503 | syms_of_nsfont (void) | 1506 | syms_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; | 1517 | static void |
| 1518 | syms_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. */ | ||
| 115 | verify (sizeof (ptrdiff_t) == sizeof (void*)); | ||
| 116 | verify (sizeof (intptr_t) == sizeof (ptrdiff_t)); | ||
| 117 | verify (sizeof (void (*)(void)) == sizeof (void*)); | ||
| 118 | verify (sizeof (ptrdiff_t) <= sizeof (Lisp_Object)); | ||
| 119 | verify (sizeof (ptrdiff_t) <= sizeof (EMACS_INT)); | ||
| 120 | verify (sizeof (off_t) == sizeof (int32_t) || | ||
| 121 | sizeof (off_t) == sizeof (int64_t)); | ||
| 122 | verify (CHAR_BIT == 8); | ||
| 123 | |||
| 124 | #define DIVIDE_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) | ||
| 125 | |||
| 126 | static const char dump_magic[16] = { | ||
| 127 | 'D', 'U', 'M', 'P', 'E', 'D', | ||
| 128 | 'G', 'N', 'U', | ||
| 129 | 'E', 'M', 'A', 'C', 'S' | ||
| 130 | }; | ||
| 131 | |||
| 132 | static pdumper_hook dump_hooks[24]; | ||
| 133 | static int nr_dump_hooks = 0; | ||
| 134 | |||
| 135 | static struct | ||
| 136 | { | ||
| 137 | void *mem; | ||
| 138 | int sz; | ||
| 139 | } remembered_data[32]; | ||
| 140 | static int nr_remembered_data = 0; | ||
| 141 | |||
| 142 | typedef 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))) | ||
| 147 | static void | ||
| 148 | dump_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 | |||
| 159 | static ssize_t dump_read_all (int fd, void *buf, size_t bytes_to_read); | ||
| 160 | |||
| 161 | static dump_off | ||
| 162 | ptrdiff_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. */ | ||
| 171 | static int | ||
| 172 | dump_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 | |||
| 184 | enum 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 | |||
| 206 | enum 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 | |||
| 237 | struct 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. */ | ||
| 253 | static void | ||
| 254 | emacs_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 | |||
| 261 | struct 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 | ||
| 273 | verify (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)) | ||
| 285 | verify (DUMP_ALIGNMENT >= GCALIGNMENT); | ||
| 286 | |||
| 287 | struct dump_reloc | ||
| 288 | { | ||
| 289 | uint32_t raw_offset : DUMP_RELOC_OFFSET_BITS; | ||
| 290 | ENUM_BF (dump_reloc_type) type : DUMP_RELOC_TYPE_BITS; | ||
| 291 | }; | ||
| 292 | verify (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. */ | ||
| 297 | static void | ||
| 298 | dump_reloc_set_type (struct dump_reloc *reloc, enum dump_reloc_type type) | ||
| 299 | { | ||
| 300 | reloc->type = type; | ||
| 301 | eassert (reloc->type == type); | ||
| 302 | } | ||
| 303 | |||
| 304 | static dump_off | ||
| 305 | dump_reloc_get_offset (struct dump_reloc reloc) | ||
| 306 | { | ||
| 307 | return reloc.raw_offset << DUMP_RELOC_ALIGNMENT_BITS; | ||
| 308 | } | ||
| 309 | |||
| 310 | static void | ||
| 311 | dump_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 | |||
| 321 | static 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. */ | ||
| 346 | struct 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. */ | ||
| 392 | struct dump_tailq | ||
| 393 | { | ||
| 394 | Lisp_Object head; | ||
| 395 | Lisp_Object tail; | ||
| 396 | intptr_t length; | ||
| 397 | }; | ||
| 398 | |||
| 399 | /* Queue of objects to dump. */ | ||
| 400 | struct 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 | |||
| 427 | enum 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. */ | ||
| 438 | struct 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. */ | ||
| 474 | struct 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. */ | ||
| 555 | enum 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. */ | ||
| 567 | enum link_weight_enum | ||
| 568 | { | ||
| 569 | WEIGHT_NONE_VALUE = 0, | ||
| 570 | WEIGHT_NORMAL_VALUE = 1000, | ||
| 571 | WEIGHT_STRONG_VALUE = 1200, | ||
| 572 | }; | ||
| 573 | |||
| 574 | struct 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 | |||
| 588 | static dump_off dump_object (struct dump_context *ctx, Lisp_Object object); | ||
| 589 | static dump_off dump_object_for_offset ( | ||
| 590 | struct dump_context *ctx, Lisp_Object object); | ||
| 591 | |||
| 592 | /* Like the Lisp function `push'. Return NEWELT. */ | ||
| 593 | static Lisp_Object | ||
| 594 | dump_push (Lisp_Object *where, Lisp_Object newelt) | ||
| 595 | { | ||
| 596 | *where = Fcons (newelt, *where); | ||
| 597 | return newelt; | ||
| 598 | } | ||
| 599 | |||
| 600 | /* Like the Lisp function `pop'. */ | ||
| 601 | static Lisp_Object | ||
| 602 | dump_pop (Lisp_Object *where) | ||
| 603 | { | ||
| 604 | Lisp_Object ret = XCAR (*where); | ||
| 605 | *where = XCDR (*where); | ||
| 606 | return ret; | ||
| 607 | } | ||
| 608 | |||
| 609 | static bool | ||
| 610 | dump_tracking_referrers_p (struct dump_context *ctx) | ||
| 611 | { | ||
| 612 | return !NILP (ctx->referrers); | ||
| 613 | } | ||
| 614 | |||
| 615 | static void | ||
| 616 | dump_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. */ | ||
| 650 | static void | ||
| 651 | DUMP_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 | |||
| 659 | static Lisp_Object | ||
| 660 | dump_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 | |||
| 668 | static void | ||
| 669 | print_paths_to_root (struct dump_context *ctx, Lisp_Object object); | ||
| 670 | |||
| 671 | static void dump_remember_cold_op (struct dump_context *ctx, | ||
| 672 | enum cold_op op, | ||
| 673 | Lisp_Object arg); | ||
| 674 | |||
| 675 | _Noreturn | ||
| 676 | static void | ||
| 677 | error_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 | |||
| 686 | static uintptr_t | ||
| 687 | emacs_basis (void) | ||
| 688 | { | ||
| 689 | return (uintptr_t) &Vpurify_flag; | ||
| 690 | } | ||
| 691 | |||
| 692 | static void * | ||
| 693 | emacs_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 | |||
| 700 | static dump_off | ||
| 701 | emacs_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). */ | ||
| 712 | static bool | ||
| 713 | dump_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 | */ | ||
| 727 | static bool | ||
| 728 | dump_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 | |||
| 758 | DEFINE_FROMLISP_FUNC (intmax_t_from_lisp, intmax_t); | ||
| 759 | DEFINE_TOLISP_FUNC (intmax_t_to_lisp, intmax_t); | ||
| 760 | DEFINE_FROMLISP_FUNC (dump_off_from_lisp, dump_off); | ||
| 761 | DEFINE_TOLISP_FUNC (dump_off_to_lisp, dump_off); | ||
| 762 | |||
| 763 | static void | ||
| 764 | dump_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 | |||
| 774 | static Lisp_Object | ||
| 775 | make_eq_hash_table (void) | ||
| 776 | { | ||
| 777 | return CALLN (Fmake_hash_table, QCtest, Qeq); | ||
| 778 | } | ||
| 779 | |||
| 780 | static void | ||
| 781 | dump_tailq_init (struct dump_tailq *tailq) | ||
| 782 | { | ||
| 783 | tailq->head = tailq->tail = Qnil; | ||
| 784 | tailq->length = 0; | ||
| 785 | } | ||
| 786 | |||
| 787 | static intptr_t | ||
| 788 | dump_tailq_length (const struct dump_tailq *tailq) | ||
| 789 | { | ||
| 790 | return tailq->length; | ||
| 791 | } | ||
| 792 | |||
| 793 | __attribute__((unused)) | ||
| 794 | static void | ||
| 795 | dump_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)) | ||
| 805 | static void | ||
| 806 | dump_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 | |||
| 823 | static bool | ||
| 824 | dump_tailq_empty_p (struct dump_tailq *tailq) | ||
| 825 | { | ||
| 826 | return NILP (tailq->head); | ||
| 827 | } | ||
| 828 | |||
| 829 | static Lisp_Object | ||
| 830 | dump_tailq_peek (struct dump_tailq *tailq) | ||
| 831 | { | ||
| 832 | eassert (!dump_tailq_empty_p (tailq)); | ||
| 833 | return XCAR (tailq->head); | ||
| 834 | } | ||
| 835 | |||
| 836 | static Lisp_Object | ||
| 837 | dump_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 | |||
| 849 | static void | ||
| 850 | dump_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 | |||
| 859 | static void | ||
| 860 | dump_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 | |||
| 873 | static void | ||
| 874 | dump_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 | |||
| 880 | static dump_off | ||
| 881 | dump_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 | |||
| 896 | static dump_off | ||
| 897 | dump_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. */ | ||
| 912 | static dump_off | ||
| 913 | dump_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 | |||
| 920 | static void | ||
| 921 | dump_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 | |||
| 930 | static void | ||
| 931 | dump_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. */ | ||
| 944 | static void* | ||
| 945 | dump_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 | |||
| 958 | static void | ||
| 959 | dump_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 | |||
| 970 | static bool | ||
| 971 | dump_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 | |||
| 995 | static void | ||
| 996 | dump_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 | |||
| 1006 | static void | ||
| 1007 | dump_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 | |||
| 1091 | static float | ||
| 1092 | dump_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. */ | ||
| 1110 | static float | ||
| 1111 | dump_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. */ | ||
| 1141 | static float | ||
| 1142 | dump_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. */ | ||
| 1175 | static dump_off | ||
| 1176 | dump_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. */ | ||
| 1190 | static void | ||
| 1191 | dump_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. */ | ||
| 1227 | static Lisp_Object | ||
| 1228 | dump_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. */ | ||
| 1356 | static bool | ||
| 1357 | dump_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 | |||
| 1368 | static void | ||
| 1369 | dump_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 | |||
| 1400 | static void | ||
| 1401 | print_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 | |||
| 1418 | static void | ||
| 1419 | print_paths_to_root (struct dump_context *ctx, Lisp_Object object) | ||
| 1420 | { | ||
| 1421 | print_paths_to_root_1 (ctx, object, 0); | ||
| 1422 | } | ||
| 1423 | |||
| 1424 | static void | ||
| 1425 | dump_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(). */ | ||
| 1439 | static void | ||
| 1440 | dump_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. */ | ||
| 1455 | static void | ||
| 1456 | dump_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. */ | ||
| 1488 | static void | ||
| 1489 | dump_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. */ | ||
| 1505 | static void | ||
| 1506 | dump_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). */ | ||
| 1539 | static void | ||
| 1540 | dump_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 | */ | ||
| 1570 | static void | ||
| 1571 | dump_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 | |||
| 1599 | DEFINE_EMACS_IMMEDIATE_FN (dump_emacs_reloc_immediate_lv, Lisp_Object); | ||
| 1600 | DEFINE_EMACS_IMMEDIATE_FN (dump_emacs_reloc_immediate_ptrdiff_t, ptrdiff_t); | ||
| 1601 | DEFINE_EMACS_IMMEDIATE_FN (dump_emacs_reloc_immediate_emacs_int, EMACS_INT); | ||
| 1602 | DEFINE_EMACS_IMMEDIATE_FN (dump_emacs_reloc_immediate_int, int); | ||
| 1603 | DEFINE_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. */ | ||
| 1607 | static void | ||
| 1608 | dump_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. */ | ||
| 1626 | static void | ||
| 1627 | dump_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. */ | ||
| 1655 | static void | ||
| 1656 | dump_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 | |||
| 1672 | enum 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 | |||
| 1680 | enum 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 | */ | ||
| 1695 | static void | ||
| 1696 | dump_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. */ | ||
| 1716 | static void | ||
| 1717 | dump_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 | |||
| 1738 | static void | ||
| 1739 | dump_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. */ | ||
| 1768 | static void | ||
| 1769 | dump_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 | |||
| 1778 | static dump_off | ||
| 1779 | field_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 | |||
| 1789 | static void | ||
| 1790 | cpyptr (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 | |||
| 1803 | static void | ||
| 1804 | dump_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 | */ | ||
| 1895 | static void | ||
| 1896 | dump_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. */ | ||
| 1919 | static void | ||
| 1920 | dump_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. */ | ||
| 1931 | static void | ||
| 1932 | dump_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. */ | ||
| 1943 | static void | ||
| 1944 | dump_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 | */ | ||
| 1969 | static void | ||
| 1970 | dump_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 | |||
| 1991 | static 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 | |||
| 2009 | static dump_off | ||
| 2010 | finish_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 | |||
| 2018 | static void | ||
| 2019 | dump_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 | |||
| 2033 | static dump_off | ||
| 2034 | dump_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 | |||
| 2046 | static dump_off | ||
| 2047 | dump_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 | |||
| 2094 | static dump_off | ||
| 2095 | dump_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 | |||
| 2140 | static dump_off | ||
| 2141 | dump_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 | |||
| 2169 | static dump_off | ||
| 2170 | dump_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 | |||
| 2182 | static void | ||
| 2183 | dump_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 | |||
| 2196 | static dump_off | ||
| 2197 | dump_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 | |||
| 2213 | struct bignum_reload_info | ||
| 2214 | { | ||
| 2215 | dump_off data_location; | ||
| 2216 | dump_off nlimbs; | ||
| 2217 | }; | ||
| 2218 | |||
| 2219 | static dump_off | ||
| 2220 | dump_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 | |||
| 2258 | static dump_off | ||
| 2259 | dump_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 | |||
| 2271 | static dump_off | ||
| 2272 | dump_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 | |||
| 2285 | static dump_off | ||
| 2286 | dump_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 | |||
| 2299 | static dump_off | ||
| 2300 | dump_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 | |||
| 2316 | static dump_off | ||
| 2317 | dump_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 | |||
| 2332 | static dump_off | ||
| 2333 | dump_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 | |||
| 2346 | static dump_off | ||
| 2347 | dump_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 | |||
| 2381 | static dump_off | ||
| 2382 | dump_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 | |||
| 2406 | static dump_off | ||
| 2407 | dump_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 | |||
| 2416 | static void | ||
| 2417 | dump_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 | |||
| 2424 | static void | ||
| 2425 | dump_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 | |||
| 2452 | static dump_off | ||
| 2453 | dump_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 | |||
| 2549 | static dump_off | ||
| 2550 | dump_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. */ | ||
| 2649 | static bool | ||
| 2650 | dump_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. */ | ||
| 2671 | static Lisp_Object | ||
| 2672 | hash_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. */ | ||
| 2684 | static void | ||
| 2685 | check_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 | |||
| 2712 | static dump_off | ||
| 2713 | dump_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 | |||
| 2782 | static dump_off | ||
| 2783 | dump_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 | |||
| 2919 | static dump_off | ||
| 2920 | dump_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 | |||
| 2936 | static dump_off | ||
| 2937 | dump_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 | |||
| 2954 | static void | ||
| 2955 | fill_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 | |||
| 2964 | static dump_off | ||
| 2965 | dump_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 | |||
| 2973 | static dump_off | ||
| 2974 | dump_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 | */ | ||
| 3085 | static dump_off | ||
| 3086 | dump_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. */ | ||
| 3182 | static dump_off | ||
| 3183 | dump_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 | |||
| 3190 | static dump_off | ||
| 3191 | dump_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 | |||
| 3232 | static dump_off | ||
| 3233 | dump_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 | |||
| 3246 | static void | ||
| 3247 | dump_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 | |||
| 3258 | static void | ||
| 3259 | dump_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. */ | ||
| 3283 | static void | ||
| 3284 | dump_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. */ | ||
| 3296 | static void | ||
| 3297 | dump_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 | |||
| 3311 | static void | ||
| 3312 | dump_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 | |||
| 3357 | static void | ||
| 3358 | dump_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 | |||
| 3374 | static void | ||
| 3375 | dump_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 | |||
| 3390 | static void | ||
| 3391 | dump_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 | |||
| 3415 | static void | ||
| 3416 | dump_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 | |||
| 3435 | static void | ||
| 3436 | dump_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 | |||
| 3486 | static void | ||
| 3487 | read_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. */ | ||
| 3514 | static void | ||
| 3515 | dump_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. */ | ||
| 3538 | static void | ||
| 3539 | dump_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 | |||
| 3611 | static void | ||
| 3612 | dump_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. */ | ||
| 3625 | static dump_off | ||
| 3626 | dump_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 | |||
| 3634 | static void | ||
| 3635 | dump_check_emacs_off (dump_off emacs_off) | ||
| 3636 | { | ||
| 3637 | eassert (labs (emacs_off) <= 60*1024*1024); | ||
| 3638 | } | ||
| 3639 | |||
| 3640 | static struct dump_reloc | ||
| 3641 | dump_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 | |||
| 3653 | static void | ||
| 3654 | dump_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 | ||
| 3669 | static Lisp_Object | ||
| 3670 | dump_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 | */ | ||
| 3686 | static struct emacs_reloc | ||
| 3687 | decode_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 | |||
| 3778 | static void | ||
| 3779 | dump_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 | |||
| 3788 | static Lisp_Object | ||
| 3789 | dump_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 | |||
| 3832 | typedef void (*drain_reloc_handler)(struct dump_context *, Lisp_Object); | ||
| 3833 | typedef Lisp_Object (*drain_reloc_merger)(Lisp_Object a, Lisp_Object b); | ||
| 3834 | |||
| 3835 | static void | ||
| 3836 | drain_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 | |||
| 3868 | static void | ||
| 3869 | dump_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 | |||
| 3962 | static void | ||
| 3963 | dump_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 | |||
| 3979 | static void | ||
| 3980 | dump_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 | |||
| 3986 | static void | ||
| 3987 | dump_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 | |||
| 4001 | static void | ||
| 4002 | dump_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 | |||
| 4016 | DEFUN ("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. | ||
| 4020 | If TRACK-REFERRERS is non-nil, keep additional debugging information | ||
| 4021 | that can help track down the provenance of unsupported object | ||
| 4022 | types. */) | ||
| 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 | |||
| 4272 | DEFUN ("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 | |||
| 4284 | DEFUN ("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 | |||
| 4296 | void | ||
| 4297 | pdumper_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 | |||
| 4305 | static void | ||
| 4306 | pdumper_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 | |||
| 4315 | void | ||
| 4316 | pdumper_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 | |||
| 4323 | void | ||
| 4324 | pdumper_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 */ | ||
| 4331 | enum dump_memory_protection { | ||
| 4332 | DUMP_MEMORY_ACCESS_NONE = 1, | ||
| 4333 | DUMP_MEMORY_ACCESS_READ = 2, | ||
| 4334 | DUMP_MEMORY_ACCESS_READWRITE = 3, | ||
| 4335 | }; | ||
| 4336 | |||
| 4337 | static void * | ||
| 4338 | dump_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 | |||
| 4385 | static void * | ||
| 4386 | dump_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. */ | ||
| 4444 | static void * | ||
| 4445 | dump_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(). */ | ||
| 4460 | static void | ||
| 4461 | dump_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 | |||
| 4478 | static void * | ||
| 4479 | dump_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 | |||
| 4552 | static void * | ||
| 4553 | dump_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. */ | ||
| 4601 | static void * | ||
| 4602 | dump_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. */ | ||
| 4623 | static void | ||
| 4624 | dump_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 | |||
| 4641 | struct 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 | |||
| 4649 | struct 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. */ | ||
| 4658 | static void | ||
| 4659 | dump_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 | |||
| 4676 | static void | ||
| 4677 | dump_mmap_discard_contents (struct dump_memory_map *map) | ||
| 4678 | { | ||
| 4679 | if (map->mapping) | ||
| 4680 | dump_discard_mem (map->mapping, map->spec.size); | ||
| 4681 | } | ||
| 4682 | |||
| 4683 | static void | ||
| 4684 | dump_mmap_reset (struct dump_memory_map *map) | ||
| 4685 | { | ||
| 4686 | map->mapping = NULL; | ||
| 4687 | map->release = NULL; | ||
| 4688 | map->private = NULL; | ||
| 4689 | } | ||
| 4690 | |||
| 4691 | static void | ||
| 4692 | dump_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. */ | ||
| 4700 | struct dump_memory_map_heap_control_block { | ||
| 4701 | int refcount; | ||
| 4702 | void *mem; | ||
| 4703 | }; | ||
| 4704 | |||
| 4705 | static void | ||
| 4706 | dump_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 | |||
| 4716 | static void | ||
| 4717 | dump_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. */ | ||
| 4724 | static bool | ||
| 4725 | dump_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 | |||
| 4776 | static void | ||
| 4777 | dump_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 | |||
| 4785 | static bool | ||
| 4786 | needs_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 | |||
| 4795 | static bool | ||
| 4796 | dump_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. */ | ||
| 4898 | static bool | ||
| 4899 | dump_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 | |||
| 4925 | typedef uint_fast32_t dump_bitset_word; | ||
| 4926 | |||
| 4927 | struct dump_bitset { | ||
| 4928 | dump_bitset_word *restrict bits; | ||
| 4929 | ptrdiff_t number_words; | ||
| 4930 | }; | ||
| 4931 | |||
| 4932 | static bool | ||
| 4933 | dump_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 | |||
| 4944 | static void | ||
| 4945 | dump_bitset_destroy (struct dump_bitset *bitset) | ||
| 4946 | { | ||
| 4947 | free (bitset->bits); | ||
| 4948 | } | ||
| 4949 | |||
| 4950 | static dump_bitset_word * | ||
| 4951 | dump_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 | |||
| 4961 | static bool | ||
| 4962 | dump_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 | |||
| 4972 | static void | ||
| 4973 | dump_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 | |||
| 4988 | static void | ||
| 4989 | dump_bitset_set_bit (struct dump_bitset *bitset, size_t bit_number) | ||
| 4990 | { | ||
| 4991 | dump_bitset__set_bit_value (bitset, bit_number, true); | ||
| 4992 | } | ||
| 4993 | |||
| 4994 | static void | ||
| 4995 | dump_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 | |||
| 5001 | struct 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 | |||
| 5013 | struct pdumper_loaded_dump dump_public; | ||
| 5014 | struct 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. */ | ||
| 5023 | static void * | ||
| 5024 | dump_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. */ | ||
| 5035 | static uintptr_t | ||
| 5036 | dump_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. */ | ||
| 5047 | static void | ||
| 5048 | dump_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. */ | ||
| 5059 | static void | ||
| 5060 | dump_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. */ | ||
| 5076 | static const struct dump_reloc * | ||
| 5077 | dump_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 | |||
| 5107 | static bool | ||
| 5108 | dump_loaded_p (void) | ||
| 5109 | { | ||
| 5110 | return dump_public.start != 0; | ||
| 5111 | } | ||
| 5112 | |||
| 5113 | bool | ||
| 5114 | pdumper_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 | |||
| 5123 | enum Lisp_Type | ||
| 5124 | pdumper_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 | |||
| 5138 | bool | ||
| 5139 | pdumper_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 | |||
| 5150 | void | ||
| 5151 | pdumper_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 | |||
| 5162 | void | ||
| 5163 | pdumper_clear_marks_impl (void) | ||
| 5164 | { | ||
| 5165 | dump_bitset_clear (&dump_private.mark_bits); | ||
| 5166 | } | ||
| 5167 | |||
| 5168 | static ssize_t | ||
| 5169 | dump_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. */ | ||
| 5195 | static int | ||
| 5196 | dump_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 | |||
| 5206 | static Lisp_Object | ||
| 5207 | dump_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. */ | ||
| 5242 | static inline void | ||
| 5243 | dump_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 | |||
| 5293 | static void | ||
| 5294 | dump_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 | |||
| 5304 | static void | ||
| 5305 | dump_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 | |||
| 5355 | static void | ||
| 5356 | dump_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 | |||
| 5366 | enum 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. */ | ||
| 5375 | static double | ||
| 5376 | subtract_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. */ | ||
| 5387 | enum pdumper_load_result | ||
| 5388 | pdumper_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 (§ions, 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 (§ions[DS_DISCARDABLE]); | ||
| 5529 | for (int i = 0; i < ARRAYELTS (sections); ++i) | ||
| 5530 | dump_mmap_reset (§ions[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 (§ions[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 | |||
| 5554 | DEFUN ("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 | |||
| 5577 | void | ||
| 5578 | syms_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 | |||
| 3 | Copyright (C) 2016 Free Software Foundation, | ||
| 4 | Inc. | ||
| 5 | |||
| 6 | This file is part of GNU Emacs. | ||
| 7 | |||
| 8 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 9 | it under the terms of the GNU General Public License as published by | ||
| 10 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 11 | your option) any later version. | ||
| 12 | |||
| 13 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | GNU General Public License for more details. | ||
| 17 | |||
| 18 | You should have received a copy of the GNU General Public License | ||
| 19 | along 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 | |||
| 26 | INLINE_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 | |||
| 54 | extern void pdumper_remember_scalar_impl (void *data, ptrdiff_t nbytes); | ||
| 55 | |||
| 56 | INLINE | ||
| 57 | void | ||
| 58 | pdumper_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 | |||
| 68 | extern 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. */ | ||
| 74 | INLINE | ||
| 75 | void | ||
| 76 | pdumper_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 | |||
| 86 | typedef void (*pdumper_hook)(void); | ||
| 87 | extern void pdumper_do_now_and_after_load_impl (pdumper_hook hook); | ||
| 88 | |||
| 89 | INLINE void | ||
| 90 | pdumper_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 | |||
| 122 | enum 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 | |||
| 134 | enum pdumper_load_result pdumper_load (const char *dump_filename); | ||
| 135 | |||
| 136 | struct pdumper_loaded_dump { | ||
| 137 | uintptr_t start; | ||
| 138 | uintptr_t end; | ||
| 139 | }; | ||
| 140 | |||
| 141 | #ifdef HAVE_PDUMPER | ||
| 142 | extern 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. */ | ||
| 148 | INLINE _GL_ATTRIBUTE_CONST | ||
| 149 | bool | ||
| 150 | pdumper_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 | |||
| 161 | extern 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. */ | ||
| 167 | INLINE _GL_ATTRIBUTE_CONST | ||
| 168 | bool | ||
| 169 | pdumper_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 | |||
| 180 | extern 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. */ | ||
| 185 | INLINE _GL_ATTRIBUTE_CONST | ||
| 186 | enum Lisp_Type | ||
| 187 | pdumper_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. */ | ||
| 201 | INLINE _GL_ATTRIBUTE_CONST | ||
| 202 | bool | ||
| 203 | pdumper_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 | |||
| 213 | extern 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. */ | ||
| 218 | INLINE | ||
| 219 | bool | ||
| 220 | pdumper_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 | |||
| 230 | extern 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. */ | ||
| 235 | INLINE | ||
| 236 | void | ||
| 237 | pdumper_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 | |||
| 247 | extern void pdumper_clear_marks_impl (void); | ||
| 248 | |||
| 249 | /* Clear all the mark bits for pdumper objects. */ | ||
| 250 | INLINE | ||
| 251 | void | ||
| 252 | pdumper_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. */ | ||
| 262 | bool pdumper_handle_page_fault (void *fault_addr_ptr); | ||
| 263 | |||
| 264 | void syms_of_pdumper (void); | ||
| 265 | |||
| 266 | INLINE_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 | ||
| 574 | static void syms_of_profiler_for_pdumper (void); | ||
| 575 | |||
| 573 | void | 576 | void |
| 574 | syms_of_profiler (void) | 577 | syms_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 | |||
| 618 | static void | ||
| 619 | syms_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 | ||
| 3390 | static void syms_of_search_for_pdumper (void); | ||
| 3391 | |||
| 3389 | void | 3392 | void |
| 3390 | syms_of_search (void) | 3393 | syms_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 | |||
| 3475 | static void | ||
| 3476 | syms_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 | ||
| 32 | char bss_sbrk_buffer[STATIC_HEAP_SIZE]; | 32 | char bss_sbrk_buffer[STATIC_HEAP_SIZE]; |
| 33 | char *max_bss_sbrk_ptr; | 33 | char *max_bss_sbrk_ptr; |
| 34 | bool bss_sbrk_did_unexec; | ||
| 35 | 34 | ||
| 36 | void * | 35 | void * |
| 37 | bss_sbrk (ptrdiff_t request_size) | 36 | bss_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 | ||
| 28 | extern char bss_sbrk_buffer[STATIC_HEAP_SIZE]; | 28 | extern char bss_sbrk_buffer[STATIC_HEAP_SIZE]; |
| 29 | extern char *max_bss_sbrk_ptr; | 29 | extern char *max_bss_sbrk_ptr; |
| 30 | extern bool bss_sbrk_did_unexec; | ||
| 31 | extern void *bss_sbrk (ptrdiff_t); | 30 | extern 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 | ||
| 1896 | static bool | 1896 | bool |
| 1897 | init_sigsegv (void) | 1897 | init_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 | ||
| 1916 | static bool | 1919 | bool |
| 1917 | init_sigsegv (void) | 1920 | init_sigsegv (void) |
| 1918 | { | 1921 | { |
| 1919 | return 0; | 1922 | return 0; |
| @@ -1963,7 +1966,7 @@ maybe_fatal_sig (int sig) | |||
| 1963 | } | 1966 | } |
| 1964 | 1967 | ||
| 1965 | void | 1968 | void |
| 1966 | init_signals (bool dumping) | 1969 | init_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 | ||
| 25 | extern void init_signals (bool); | 25 | extern void init_signals (void); |
| 26 | extern bool init_sigsegv (void); | ||
| 26 | extern void block_child_signal (sigset_t *); | 27 | extern void block_child_signal (sigset_t *); |
| 27 | extern void unblock_child_signal (sigset_t const *); | 28 | extern void unblock_child_signal (sigset_t const *); |
| 28 | extern void block_interrupt_signal (sigset_t *); | 29 | extern 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 *); |
| 94 | extern struct timespec lisp_time_argument (Lisp_Object); | 94 | extern struct timespec lisp_time_argument (Lisp_Object); |
| 95 | extern _Noreturn void time_overflow (void); | 95 | extern _Noreturn void time_overflow (void); |
| 96 | extern void init_timefns (bool); | 96 | extern void init_timefns (void); |
| 97 | extern void syms_of_timefns (void); | 97 | extern void syms_of_timefns (void); |
| 98 | 98 | ||
| 99 | INLINE_HEADER_END | 99 | INLINE_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 | ||
| 30 | union aligned_thread_state | 31 | union aligned_thread_state |
| @@ -1064,7 +1065,7 @@ init_main_thread (void) | |||
| 1064 | } | 1065 | } |
| 1065 | 1066 | ||
| 1066 | bool | 1067 | bool |
| 1067 | main_thread_p (void *ptr) | 1068 | main_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); | |||
| 295 | extern void init_threads_once (void); | 295 | extern void init_threads_once (void); |
| 296 | extern void init_threads (void); | 296 | extern void init_threads (void); |
| 297 | extern void syms_of_threads (void); | 297 | extern void syms_of_threads (void); |
| 298 | extern bool main_thread_p (void *); | 298 | extern bool main_thread_p (const void *); |
| 299 | extern bool in_current_thread (void); | 299 | extern bool in_current_thread (void); |
| 300 | 300 | ||
| 301 | typedef int select_func (int, fd_set *, fd_set *, fd_set *, | 301 | typedef 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 | ||
| 293 | void | 294 | void |
| 294 | init_timefns (bool dumping) | 295 | init_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 | ||
| 1738 | static void | ||
| 1739 | syms_of_timefns_for_pdumper (void) | ||
| 1740 | { | ||
| 1741 | mpz_init_set_ui (ztrillion, 1000000); | ||
| 1742 | mpz_mul_ui (ztrillion, ztrillion, 1000000); | ||
| 1743 | } | ||
| 1744 | #endif | ||
| 1745 | |||
| 1732 | void | 1746 | void |
| 1733 | syms_of_timefns (void) | 1747 | syms_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 | ||
| 42 | extern BOOL ctrl_c_handler (unsigned long type); | ||
| 43 | |||
| 44 | extern char my_begdata[]; | 42 | extern char my_begdata[]; |
| 45 | extern char my_begbss[]; | 43 | extern char my_begbss[]; |
| 46 | extern char *my_begbss_static; | 44 | extern char *my_begbss_static; |
| @@ -70,84 +68,10 @@ PCHAR bss_start_static = 0; | |||
| 70 | DWORD_PTR bss_size_static = 0; | 68 | DWORD_PTR bss_size_static = 0; |
| 71 | DWORD_PTR extra_bss_size_static = 0; | 69 | DWORD_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 | |||
| 80 | extern 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 ()). */ | ||
| 86 | void _start (void); | ||
| 87 | |||
| 88 | void | ||
| 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! */ |
| 120 | int | ||
| 121 | open_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 | ||
| 152 | int | 76 | int |
| 153 | open_output_file (file_data *p_file, char *filename, unsigned long size) | 77 | open_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. */ | ||
| 191 | void | ||
| 192 | close_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. */ | ||
| 225 | IMAGE_SECTION_HEADER * | ||
| 226 | rva_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. */ |
| @@ -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. */ | ||
| 9934 | const char * | ||
| 9935 | w32_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 |
| @@ -185,6 +185,8 @@ extern MultiByteToWideChar_Proc pMultiByteToWideChar; | |||
| 185 | extern WideCharToMultiByte_Proc pWideCharToMultiByte; | 185 | extern WideCharToMultiByte_Proc pWideCharToMultiByte; |
| 186 | extern DWORD multiByteToWideCharFlags; | 186 | extern DWORD multiByteToWideCharFlags; |
| 187 | 187 | ||
| 188 | extern const char *w32_relocate (const char *); | ||
| 189 | |||
| 188 | extern void init_environment (char **); | 190 | extern void init_environment (char **); |
| 189 | extern void check_windows_init_file (void); | 191 | extern void check_windows_init_file (void); |
| 190 | extern void syms_of_ntproc (void); | 192 | extern 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 | |||
| 2630 | static void syms_of_w32font_for_pdumper (void); | ||
| 2631 | |||
| 2627 | void | 2632 | void |
| 2628 | syms_of_w32font (void) | 2633 | syms_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 | |||
| 2814 | static void | ||
| 2815 | syms_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 { | |||
| 223 | typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T); | 223 | typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T); |
| 224 | #endif | 224 | #endif |
| 225 | 225 | ||
| 226 | #ifdef HAVE_PDUMPER | ||
| 227 | BOOL using_dynamic_heap = FALSE; | ||
| 228 | #endif | ||
| 229 | |||
| 226 | void | 230 | void |
| 227 | init_heap (void) | 231 | init_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 | ||
| 82 | static CRITICAL_SECTION crit_sig; | 82 | static CRITICAL_SECTION crit_sig; |
| 83 | 83 | ||
| 84 | |||
| 85 | extern 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 | |||
| 94 | extern 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 ()). */ | ||
| 100 | void _start (void); | ||
| 101 | |||
| 102 | void | ||
| 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. */ |
| 86 | signal_handler | 131 | signal_handler |
| @@ -1528,6 +1573,78 @@ waitpid (pid_t pid, int *status, int options) | |||
| 1528 | return pid; | 1573 | return pid; |
| 1529 | } | 1574 | } |
| 1530 | 1575 | ||
| 1576 | int | ||
| 1577 | open_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. */ | ||
| 1610 | IMAGE_SECTION_HEADER * | ||
| 1611 | rva_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. */ | ||
| 1637 | void | ||
| 1638 | close_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 | ||
| 41 | struct uniscribe_font_info | 42 | struct 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. */ |
| 1177 | void syms_of_w32uniscribe (void); | 1178 | void syms_of_w32uniscribe (void); |
| 1178 | 1179 | ||
| 1180 | static void syms_of_w32uniscribe_for_pdumper (void); | ||
| 1181 | |||
| 1179 | void | 1182 | void |
| 1180 | syms_of_w32uniscribe (void) | 1183 | syms_of_w32uniscribe (void) |
| 1181 | { | 1184 | { |
| 1185 | pdumper_do_now_and_after_load (syms_of_w32uniscribe_for_pdumper); | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | static void | ||
| 1189 | syms_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 | ||
| 46 | static ptrdiff_t count_windows (struct window *); | 47 | static ptrdiff_t count_windows (struct window *); |
| 47 | static ptrdiff_t get_leaf_windows (struct window *, struct window **, | 48 | static 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 | |||
| 7881 | static void init_window_once_for_pdumper (void); | ||
| 7882 | |||
| 7879 | void | 7883 | void |
| 7880 | init_window_once (void) | 7884 | init_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 | |||
| 7901 | static 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. |
| 7947 | The function is called with one argument, the buffer to be displayed. | 7987 | The 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 | ||
| 1081 | static void syms_of_xfont_for_pdumper (void); | ||
| 1080 | 1082 | ||
| 1081 | struct font_driver const xfont_driver = | 1083 | struct 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 | |||
| 1110 | static void | ||
| 1111 | syms_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 | ||
| 755 | static void syms_of_xftfont_for_pdumper (void); | ||
| 756 | |||
| 754 | struct font_driver const xftfont_driver = | 757 | struct 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) | |||
| 802 | This is needed with some fonts to correct vertical overlap of glyphs. */); | 805 | This 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 | ||
| 811 | static void | ||
| 812 | syms_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 | |||
| 2406 | static void syms_of_xmenu_for_pdumper (void); | ||
| 2407 | |||
| 2404 | void | 2408 | void |
| 2405 | syms_of_xmenu (void) | 2409 | syms_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 | |||
| 2427 | static void | ||
| 2428 | syms_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 | |||
| 2618 | static void syms_of_xselect_for_pdumper (void); | ||
| 2619 | |||
| 2616 | void | 2620 | void |
| 2617 | syms_of_xselect (void) | 2621 | syms_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 | |||
| 2720 | static void | ||
| 2721 | syms_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 | |||
| 1023 | syms_of_xsettings (void) | 1024 | syms_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 | |||
| 13298 | syms_of_xterm (void) | 13299 | syms_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"); |