

index d295797347..53f41f0f3e 100644

--- a/

+++ b/ diff --git a/.gitignore b/.gitignoreindex d295797347..53f41f0f3e 100644--- a/ .gitignore +++ b/ .gitignore @@ -171,6 +171,7 @@ lib-src/emacsclient lib-src/etags lib-src/hexl lib-src/make-docfile +lib-src/make-fingerprint lib-src/movemail lib-src/profile lib-src/test-distrib @@ -184,6 +185,10 @@ src/bootstrap-emacs src/emacs src/emacs-[0-9]* src/temacs +src/temacs.in +src/fingerprint.c +src/dmpstruct.h +src/*.pdmp # Character-set info. admin/charsets/jisx2131-filter

index cd3a0a9293..b6cd04d1f3 100644

--- a/

+++ b/ diff --git a/Makefile.in b/Makefile.inindex cd3a0a9293..b6cd04d1f3 100644--- a/ Makefile.in +++ b/ Makefile.in @@ -66,6 +66,8 @@ SHELL = @SHELL@ +DUMPING=@DUMPING@ + # This only matters when inheriting a CDPATH not starting with the # current directory. CDPATH= @@ -491,6 +493,9 @@ install-arch-dep: src install-arch-indep install-etcdoc install-$(NTDIR) $(MAKE) -C lib-src install ifeq (${ns_self_contained},no) ${INSTALL_PROGRAM} $(INSTALL_STRIP) src/emacs${EXEEXT} "$(DESTDIR)${bindir}/$(EMACSFULL)" +ifeq (${DUMPING},pdumper) + ${INSTALL_DATA} src/emacs.pdmp "$(DESTDIR)${libexecdir}/emacs/${version}/${configuration}"/emacs.pdmp +endif -chmod 755 "$(DESTDIR)${bindir}/$(EMACSFULL)" ifndef NO_BIN_LINK rm -f "$(DESTDIR)${bindir}/$(EMACS)"

index 16a2ce059d..7529719429 100644

--- a/

+++ b/ diff --git a/configure.ac b/configure.acindex 16a2ce059d..7529719429 100644--- a/ configure.ac +++ b/ configure.ac @@ -311,6 +311,87 @@ this option's value should be 'yes', 'no', 'alsa', 'oss', or 'bsd-ossaudio'.]) ], [with_sound=$with_features]) +AC_ARG_WITH([pdumper], + AS_HELP_STRING( + [--with-pdumper=VALUE], + [enable pdumper support unconditionally + ('yes', 'no', or 'auto': default 'auto')]), + [ case "${withval}" in + yes|no|auto) val=$withval ;; + *) AC_MSG_ERROR( + ['--with-pdumper=$withval' is invalid; +this option's value should be 'yes' or 'no'.]) ;; + esac + with_pdumper=$val + ], + [with_pdumper=auto]) + +AC_ARG_WITH([unexec], + AS_HELP_STRING( + [--with-unexec=VALUE], + [enable unexec support unconditionally + ('yes', 'no', or 'auto': default 'auto')]), + [ case "${withval}" in + yes|no|auto) val=$withval ;; + *) AC_MSG_ERROR( + ['--with-unexec=$withval' is invalid; +this option's value should be 'yes' or 'no'.]) ;; + esac + with_unexec=$val + ], + [with_unexec=auto]) + +AC_ARG_WITH([dumping],[AS_HELP_STRING([--with-dumping=VALUE], + [kind of dumping to use for initial Emacs build +(VALUE one of: pdumper, unexec, none; default pdumper)])], + [ case "${withval}" in + pdumper|unexec|none) val=$withval ;; + *) AC_MSG_ERROR(['--with-dumping=$withval is invalid; +this option's value should be 'pdumper', 'unexec', or 'none'.]) + ;; + esac + with_dumping=$val + ], + [with_dumping=pdumper]) + +if test "$with_pdumper" = "auto"; then + if test "$with_dumping" = "pdumper"; then + with_pdumper=yes + else + with_pdumper=no + fi +fi + +if test "$with_unexec" = "auto"; then + if test "$with_dumping" = "unexec"; then + with_unexec=yes + else + with_unexec=no + fi +fi + +if test "$with_dumping" = "pdumper" && test "$with_pdumper" = "no"; then + AC_MSG_ERROR(['--with-dumping=pdumper' requires pdumper support]) +fi + +if test "$with_dumping" = "unexec" && test "$with_unexec" = "no"; then + AC_MSG_ERROR(['--with-dumping=unexec' requires unexec support]) +fi + +if test "$with_pdumper" = "yes"; then + AC_DEFINE(HAVE_PDUMPER, 1, [Define to build with portable dumper support]) +fi + +if test "$with_unexec" = "yes"; then + CANNOT_DUMP=no +else + CANNOT_DUMP=yes +fi + +DUMPING=$with_dumping +AC_SUBST(DUMPING) +AC_SUBST(CANNOT_DUMP) + dnl FIXME currently it is not the last. dnl This should be the last --with option, because --with-x is dnl added later on when we find the file name of X, and it's best to @@ -1215,6 +1296,10 @@ AC_PATH_PROG(GZIP_PROG, gzip) test $with_compress_install != yes && test -n "$GZIP_PROG" && \ GZIP_PROG=" # $GZIP_PROG # (disabled by configure --without-compress-install)" +if test "$with_dumping" = "unexec" && test "$opsys" = "nacl"; then + AC_MSG_ERROR([nacl is not compatible with --with-dumping=unexec]) +fi + AC_CACHE_CHECK([for 'find' args to delete a file], [emacs_cv_find_delete], [if touch conftest.tmp && find conftest.tmp -delete 2>/dev/null && @@ -1227,25 +1312,21 @@ AC_SUBST([FIND_DELETE]) PAXCTL_dumped= PAXCTL_notdumped= -if test "$CANNOT_DUMP" != yes; then - if test $opsys = gnu-linux; then - if test "${SETFATTR+set}" != set; then - AC_CACHE_CHECK([for setfattr], - [emacs_cv_prog_setfattr], - [touch conftest.tmp - if (setfattr -n user.pax.flags conftest.tmp) >/dev/null 2>&1; then - emacs_cv_prog_setfattr=yes - else - emacs_cv_prog_setfattr=no - fi]) - if test "$emacs_cv_prog_setfattr" = yes; then - PAXCTL_notdumped='$(SETFATTR) -n user.pax.flags -v er' - SETFATTR=setfattr - else - SETFATTR= - fi - rm -f conftest.tmp - AC_SUBST([SETFATTR]) +if test "$CANNOT_DUMP" = "no" && test $opsys = gnu-linux; then + if test "${SETFATTR+set}" != set; then + AC_CACHE_CHECK([for setfattr], + [emacs_cv_prog_setfattr], + [touch conftest.tmp + if (setfattr -n user.pax.flags conftest.tmp) >/dev/null 2>&1; then + emacs_cv_prog_setfattr=yes + else + emacs_cv_prog_setfattr=no + fi]) + if test "$emacs_cv_prog_setfattr" = yes; then + PAXCTL_notdumped='$(SETFATTR) -n user.pax.flags -v er' + SETFATTR=setfattr + else + SETFATTR= fi fi case $opsys,$PAXCTL_notdumped,$emacs_uname_r in @@ -1382,22 +1463,12 @@ AC_CACHE_CHECK([whether addresses are sanitized], [emacs_cv_sanitize_address=yes], [emacs_cv_sanitize_address=no])]) -dnl The function dump-emacs will not be defined and temacs will do -dnl (load "loadup") automatically unless told otherwise. -test "x$CANNOT_DUMP" = "x" && CANNOT_DUMP=no -case "$opsys" in - nacl) CANNOT_DUMP=yes ;; -esac - if test "$CANNOT_DUMP" = "yes"; then - AC_DEFINE(CANNOT_DUMP, 1, [Define if Emacs cannot be dumped on your system.]) + AC_DEFINE(CANNOT_DUMP, 1, [Define if Emacs should not support unexec.]) elif test "$emacs_cv_sanitize_address" = yes; then AC_MSG_WARN([[Addresses are sanitized; suggest CANNOT_DUMP=yes]]) fi -AC_SUBST(CANNOT_DUMP) - - UNEXEC_OBJ=unexelf.o case "$opsys" in # MSDOS uses unexcoff.o @@ -1476,8 +1547,9 @@ case "$opsys" in LD_SWITCH_SYSTEM="\$(LD_SWITCH_X_SITE_RPATH) $LD_SWITCH_SYSTEM" ;; esac - C_SWITCH_MACHINE= + +test "$CANNOT_DUMP" = yes || case $canonical in alpha*) AC_CHECK_DECL([__ELF__]) @@ -4064,6 +4136,9 @@ dnl No need to check for posix_memalign if aligned_alloc works. AC_CHECK_FUNCS([aligned_alloc posix_memalign], [break]) AC_CHECK_DECLS([aligned_alloc], [], [], [[#include <stdlib.h>]]) +# Dump loading +AC_CHECK_FUNCS([posix_madvise]) + dnl Cannot use AC_CHECK_FUNCS AC_CACHE_CHECK([for __builtin_frame_address], [emacs_cv_func___builtin_frame_address], @@ -5540,6 +5615,9 @@ AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D Does Emacs use toolkit scroll bars? ${USE_TOOLKIT_SCROLL_BARS} Does Emacs support Xwidgets (requires gtk3)? ${HAVE_XWIDGETS} Does Emacs have threading support in lisp? ${threads_enabled} + Does Emacs support the portable dumper? ${with_pdumper} + Does Emacs support legacy unexec dumping? ${with_unexec} + Which dumping strategy does Emacs use? ${with_dumping} "]) if test -n "${EMACSDATA}"; then

index 9c74d8eee4..387a6e3324 100644

--- a/

+++ b/ diff --git a/lib-src/Makefile.in b/lib-src/Makefile.inindex 9c74d8eee4..387a6e3324 100644--- a/ lib-src/Makefile.in +++ b/ lib-src/Makefile.in @@ -167,7 +167,7 @@ UTILITIES = profile${EXEEXT} hexl${EXEEXT} \ $(if $(with_mailutils), , movemail${EXEEXT}) \ $(and $(use_gamedir), update-game-score${EXEEXT}) -DONT_INSTALL= make-docfile${EXEEXT} +DONT_INSTALL= make-docfile${EXEEXT} make-fingerprint${EXEEXT} # Like UTILITIES, but they're not system-dependent, and should not be # deleted by the distclean target. @@ -385,6 +385,9 @@ profile${EXEEXT}: ${srcdir}/profile.c $(NTLIB) $(config_h) make-docfile${EXEEXT}: ${srcdir}/make-docfile.c $(NTLIB) $(config_h) $(AM_V_CCLD)$(CC) ${ALL_CFLAGS} $< $(NTLIB) $(LOADLIBES) -o $@ +make-fingerprint${EXEEXT}: ${srcdir}/make-fingerprint.c $(NTLIB) $(config_h) + $(AM_V_CCLD)$(CC) ${ALL_CFLAGS} $< $(NTLIB) $(LOADLIBES) -o $@ + movemail${EXEEXT}: ${srcdir}/movemail.c pop.o $(NTLIB) $(config_h) $(AM_V_CCLD)$(CC) ${ALL_CFLAGS} ${MOVE_FLAGS} $< pop.o \ $(NTLIB) $(LOADLIBES) $(LIBS_MOVE) -o $@

new file mode 100644

index 0000000000..69558a818e

--- /dev/null

+++ b/ diff --git a/lib-src/make-fingerprint.c b/lib-src/make-fingerprint.cnew file mode 100644index 0000000000..69558a818e--- /dev/null+++ b/ lib-src/make-fingerprint.c @@ -0,0 +1,113 @@ +/* Hash inputs and generate C file with the digest. + +Copyright (C) 1985-1986, 1992-1994, 1997, 1999-2016 Free Software +Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ + + +/* The arguments given to this program are all the object files that + go into building GNU Emacs. There is no special search logic to find + the files. */ + +#include <config.h> + +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysstdio.h> +#include <sha256.h> +#include <getopt.h> + +#ifdef WINDOWSNT +/* Defined to be sys_fopen in ms-w32.h, but only #ifdef emacs, so this + is really just insurance. */ +#undef fopen +#include <direct.h> +#endif /* WINDOWSNT */ + +int +main (int argc, char **argv) +{ + int c; + bool raw = false; + while (0 <= (c = getopt (argc, argv, "rh"))) + { + switch (c) + { + case 'r': + raw = true; + break; + case 'h': + printf ("make-fingerprint [-r] FILES...: compute a hash

"); + return 0; + default: + return 1; + } + } + + struct sha256_ctx ctx; + sha256_init_ctx (&ctx); + + for (int i = optind; i < argc; ++i) + { + FILE *f = fopen (argv[i], "r" FOPEN_BINARY); + if (!f) + { + fprintf (stderr, "%s: Error: could not open %s

", + argv[0], argv[i]); + return 1; + } + + char buf[128*1024]; + do + { + size_t chunksz = fread (buf, 1, sizeof (buf), f); + if (ferror (f)) + { + fprintf (stderr, "%s: Error: could not read %s

", + argv[0], argv[i]); + return 1; + } + sha256_process_bytes (buf, chunksz, &ctx); + } while (!feof (f)); + fclose (f); + } + + uint8_t digest[32]; + sha256_finish_ctx (&ctx, digest); + + if (raw) + { + for (int i = 0; i < 32; ++i) + printf ("%02X", digest[i]); + } + else + { + printf ("#include \"fingerprint.h\"

"); + printf ("

"); + printf ("const uint8_t fingerprint[32] = { "); + for (int i = 0; i < 32; ++i) + printf ("%s0x%02X", i ? ", " : "", digest[i]); + printf (" };

"); + } + + return EXIT_SUCCESS; +} + +/* make-fingerprint.c ends here */

index 90ea7edff8..44ce2929d6 100644

--- a/

+++ b/ diff --git a/lisp/cus-start.el b/lisp/cus-start.elindex 90ea7edff8..44ce2929d6 100644--- a/ lisp/cus-start.el +++ b/ lisp/cus-start.el @@ -730,7 +730,7 @@ since it could result in memory overflow and make Emacs crash." ;; If this is NOT while dumping Emacs, set up the rest of the ;; customization info. This is the stuff that is not needed ;; until someone does M-x customize etc. - (unless purify-flag + (unless dump-mode ;; Add it to the right group(s). (if (listp group) (dolist (g group) @@ -752,7 +752,7 @@ since it could result in memory overflow and make Emacs crash." ;; Record cus-start as loaded if we have set up all the info that we can. ;; Don't record it as loaded if we have only set up the standard values ;; and safe/risky properties. -(unless purify-flag +(unless dump-mode (provide 'cus-start)) ;;; cus-start.el ends here

index b12735676c..40e9ba1c14 100644

--- a/

+++ b/ diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.elindex b12735676c..40e9ba1c14 100644--- a/ lisp/emacs-lisp/pcase.el +++ b/ lisp/emacs-lisp/pcase.el @@ -63,6 +63,7 @@ ;; FIXME: Now that macroexpansion is also performed when loading an interpreted ;; file, this is not a real problem any more. (defconst pcase--memoize (make-hash-table :weakness 'key :test 'eq)) +;; (defconst pcase--memoize (make-hash-table :test 'eq)) ;; (defconst pcase--memoize-1 (make-hash-table :test 'eq)) ;; (defconst pcase--memoize-2 (make-hash-table :weakness 'key :test 'equal))

index 6ccb001e35..9948bd4a03 100644

--- a/

+++ b/ diff --git a/lisp/files.el b/lisp/files.elindex 6ccb001e35..9948bd4a03 100644--- a/ lisp/files.el +++ b/ lisp/files.el @@ -1009,7 +1009,7 @@ directory if it does not exist." ;; Make sure `user-emacs-directory' exists, ;; unless we're in batch mode or dumping Emacs. (or noninteractive - purify-flag + dump-mode (let (errtype) (if (file-directory-p user-emacs-directory) (or (file-accessible-directory-p user-emacs-directory)

index cdd8ba7c40..b07f984b58 100644

--- a/

+++ b/ diff --git a/lisp/international/characters.el b/lisp/international/characters.elindex cdd8ba7c40..b07f984b58 100644--- a/ lisp/international/characters.el +++ b/ lisp/international/characters.el @@ -1334,7 +1334,7 @@ Setup char-width-table appropriate for non-CJK language environment." ;; Setting char-script-table. -(if purify-flag +(if dump-mode ;; While dumping, we can't use require, and international is not ;; in load-path. (load "international/charscript")

index 1c7f6fa83a..023fcbc5d1 100644

--- a/

+++ b/ diff --git a/lisp/international/mule.el b/lisp/international/mule.elindex 1c7f6fa83a..023fcbc5d1 100644--- a/ lisp/international/mule.el +++ b/ lisp/international/mule.el @@ -343,7 +343,7 @@ Return t if file exists." ;; Have the original buffer current while we eval. (eval-buffer buffer nil ;; This is compatible with what `load' does. - (if purify-flag file fullname) + (if dump-mode file fullname) nil t)) (let (kill-buffer-hook kill-buffer-query-functions) (kill-buffer buffer)))

index f419f0bd4a..0f0ca15ceb 100644

--- a/

+++ b/ diff --git a/lisp/loadup.el b/lisp/loadup.elindex f419f0bd4a..0f0ca15ceb 100644--- a/ lisp/loadup.el +++ b/ lisp/loadup.el @@ -26,6 +26,9 @@ ;; This is loaded into a bare Emacs to make a dumpable one. +;; Emacs injects the variable `dump-mode' to tell us how to dump. +;; We unintern it before allowing user code to run. + ;; If you add a file to be loaded here, keep the following points in mind: ;; i) If the file is no-byte-compile, explicitly load the .el version. @@ -54,33 +57,58 @@ ;; bidi.c needs for its job. (setq redisplay--inhibit-bidi t) +(message "dump mode: %s" dump-mode) + ;; Add subdirectories to the load-path for files that might get -;; autoloaded when bootstrapping. +;; autoloaded when bootstrapping or running Emacs normally. ;; This is because PATH_DUMPLOADSEARCH is just "../lisp". -(if (or (equal (member "bootstrap" command-line-args) '("bootstrap")) +(if (or (member dump-mode '("bootstrap" "pbootstrap")) ;; FIXME this is irritatingly fragile. - (and (stringp (nth 4 command-line-args)) - (string-match "^unidata-gen\\(\\.elc?\\)?$" - (nth 4 command-line-args))) - (member (nth 7 command-line-args) '("unidata-gen-file" - "unidata-gen-charprop")) - (if (fboundp 'dump-emacs) - (string-match "src/bootstrap-emacs" (nth 0 command-line-args)) - t)) - (let ((dir (car load-path))) + (and (stringp (nth 4 command-line-args)) + (string-match "^unidata-gen\\(\\.elc?\\)?$" + (nth 4 command-line-args))) + (member (nth 7 command-line-args) '("unidata-gen-file" + "unidata-gen-charprop")) + (null dump-mode)) + (progn + ;; Find the entry in load-path that contains Emacs elisp and + ;; splice some additional directories in there for the benefit + ;; of autoload and regular Emacs use. + (let ((subdirs '("emacs-lisp" + "progmodes" + "language" + "international" + "textmodes" + "vc")) + (iter load-path)) + (while iter + (let ((dir (car iter)) + (subdirs subdirs) + esubdirs esubdir) + (while subdirs + (setq esubdir (expand-file-name (car subdirs) dir)) + (setq subdirs (cdr subdirs)) + (if (file-directory-p esubdir) + (setq esubdirs (cons esubdir esubdirs)) + (setq subdirs nil esubdirs nil))) + (if esubdirs + (progn + (setcdr iter (nconc (nreverse esubdirs) (cdr iter))) + (setq iter nil)) + (setq iter (cdr iter)) + (if (null iter) + (signal + 'error (list + (format-message + "Could not find elisp load-path: searched %S" + load-path)))))))) ;; We'll probably overflow the pure space. (setq purify-flag nil) ;; Value of max-lisp-eval-depth when compiling initially. - ;; During bootstrapping the byte-compiler is run interpreted when - ;; compiling itself, which uses a lot more stack than usual. - (setq max-lisp-eval-depth 2200) - (setq load-path (list (expand-file-name "." dir) - (expand-file-name "emacs-lisp" dir) - (expand-file-name "progmodes" dir) - (expand-file-name "language" dir) - (expand-file-name "international" dir) - (expand-file-name "textmodes" dir) - (expand-file-name "vc" dir))))) + ;; During bootstrapping the byte-compiler is run interpreted + ;; when compiling itself, which uses a lot more stack + ;; than usual. + (setq max-lisp-eval-depth 2200))) (if (eq t purify-flag) ;; Hash consing saved around 11% of pure space in my tests. @@ -88,10 +116,7 @@ (message "Using load-path %s" load-path) -;; This is a poor man's `last', since we haven't loaded subr.el yet. -(if (and (fboundp 'dump-emacs) - (or (equal (member "bootstrap" command-line-args) '("bootstrap")) - (equal (member "dump" command-line-args) '("dump")))) +(if dump-mode (progn ;; To reduce the size of dumped Emacs, we avoid making huge char-tables. (setq inhibit-load-charset-map t) @@ -350,15 +375,16 @@ lost after dumping"))) ;; file primitive. So the only workable solution to support building ;; in non-ASCII directories is to manipulate unibyte strings in the ;; current locale's encoding. -(if (and (member (car (last command-line-args)) '("dump" "bootstrap")) - (fboundp 'dump-emacs) - (multibyte-string-p default-directory)) +(if (and dump-mode (multibyte-string-p default-directory)) (error "default-directory must be unibyte when dumping Emacs!")) ;; Determine which build number to use ;; based on the executables that now exist. -(if (and (equal (last command-line-args) '("dump")) - (fboundp 'dump-emacs) +(if (and (or + (and (equal dump-mode "dump") + (fboundp 'dump-emacs)) + (and (equal dump-mode "pdump") + (fboundp 'dump-emacs-portable))) (not (eq system-type 'ms-dos))) (let* ((base (concat "emacs-" emacs-version ".")) (exelen (if (eq system-type 'windows-nt) -4)) @@ -376,8 +402,10 @@ lost after dumping"))) (message "Finding pointers to doc strings...") -(if (and (fboundp 'dump-emacs) - (equal (last command-line-args) '("dump"))) +(if (and (or (and (fboundp 'dump-emacs) + (equal dump-mode "dump")) + (and (fboundp 'dump-emacs-portable) + (equal dump-mode "pdump")))) (Snarf-documentation "DOC") (condition-case nil (Snarf-documentation "DOC") @@ -446,43 +474,55 @@ lost after dumping"))) ;; Make sure we will attempt bidi reordering henceforth. (setq redisplay--inhibit-bidi nil) -(if (and (fboundp 'dump-emacs) - (member (car (last command-line-args)) '("dump" "bootstrap"))) - (progn - ;; Prevent build-time PATH getting stored in the binary. - ;; Mainly cosmetic, but helpful for Guix. (Bug#20330) - ;; Do this here, rather than earlier, so that the above code - ;; can invoke Git commands and the like. - (setq exec-path nil) - (message "Dumping under the name emacs") +(if dump-mode + (let ((output (cond ((equal dump-mode "pdump") "emacs.pdmp") + ((equal dump-mode "dump") "emacs") + ((equal dump-mode "bootstrap") "emacs") + ((equal dump-mode "pbootstrap") "bootstrap-emacs.pdmp") + (t (error "unrecognized dump mode %s" dump-mode))))) + (message "Dumping under the name %s" output) (condition-case () - (delete-file "emacs") - (file-error nil)) - ;; We used to dump under the name xemacs, but that occasionally - ;; confused people installing Emacs (they'd install the file - ;; under the name `xemacs'), and it's inconsistent with every - ;; other GNU program's build process. - (dump-emacs "emacs" "temacs") - (message "%d pure bytes used" pure-bytes-used) + (delete-file output) + (file-error nil)) + ;; On MS-Windows, the current directory is not necessarily the + ;; same as invocation-directory. + (let (success) + (unwind-protect + (progn + (if (member dump-mode '("pdump" "pbootstrap")) + (dump-emacs-portable (expand-file-name output invocation-directory)) + (dump-emacs output "temacs") + (message "%d pure bytes used" pure-bytes-used)) + (setq success t)) + (unless success + (ignore-errors + (delete-file output))))) ;; Recompute NAME now, so that it isn't set when we dump. (if (not (or (eq system-type 'ms-dos) ;; Don't bother adding another name if we're just ;; building bootstrap-emacs. - (equal (last command-line-args) '("bootstrap")))) - (let ((name (format "emacs-%s.%d" emacs-version emacs-build-number)) - (exe (if (eq system-type 'windows-nt) ".exe" ""))) - (while (string-match "[^-+_.a-zA-Z0-9]+" name) - (setq name (concat (downcase (substring name 0 (match-beginning 0))) - "-" - (substring name (match-end 0))))) - (setq name (concat name exe)) - (message "Adding name %s" name) - ;; When this runs on Windows, invocation-directory is not - ;; necessarily the current directory. - (add-name-to-file (expand-file-name (concat "emacs" exe) - invocation-directory) - (expand-file-name name invocation-directory) - t))) + (member dump-mode '("pbootstrap" "bootstrap")))) + (let ((name (format "emacs-%s.%d" emacs-version emacs-build-number)) + (exe (if (eq system-type 'windows-nt) ".exe" ""))) + (while (string-match "[^-+_.a-zA-Z0-9]+" name) + (setq name (concat (downcase (substring name 0 (match-beginning 0))) + "-" + (substring name (match-end 0))))) + (message "Adding name %s" (concat name exe)) + ;; When this runs on Windows, invocation-directory is not + ;; necessarily the current directory. + (add-name-to-file (expand-file-name (concat "emacs" exe) + invocation-directory) + (expand-file-name (concat name exe) + invocation-directory) + t) + (when (equal dump-mode "pdump") + (message "Adding name %s" (concat name ".pdmp")) + (add-name-to-file (expand-file-name "emacs.pdmp" + invocation-directory) + (expand-file-name (concat name ".pdmp") + invocation-directory) + t)))) (kill-emacs))) ;; For machines with CANNOT_DUMP defined in config.h,

index 1011d5f953..f2410f6f2c 100644

--- a/

+++ b/ diff --git a/lisp/startup.el b/lisp/startup.elindex 1011d5f953..f2410f6f2c 100644--- a/ lisp/startup.el +++ b/ lisp/startup.el @@ -1056,7 +1056,8 @@ please check its value") (let* ((longopts '(("--no-init-file") ("--no-site-file") ("--no-x-resources") ("--debug-init") ("--user") ("--iconic") ("--icon-type") ("--quick") - ("--no-blinking-cursor") ("--basic-display"))) + ("--no-blinking-cursor") ("--basic-display") + ("--dump-file") ("--temacs"))) (argi (pop args)) (orig-argi argi) argval) @@ -1108,6 +1109,9 @@ please check its value") (push '(visibility . icon) initial-frame-alist)) ((member argi '("-nbc" "-no-blinking-cursor")) (setq no-blinking-cursor t)) + ((member argi '("-dump-file" "-temacs")) ; Handled in C + (or argval (pop args)) + (setq argval nil)) ;; Push the popped arg back on the list of arguments. (t (push argi args)

index a1966f0288..ea64af60ca 100644

--- a/

+++ b/ diff --git a/nextstep/Makefile.in b/nextstep/Makefile.inindex a1966f0288..ea64af60ca 100644--- a/ nextstep/Makefile.in +++ b/ nextstep/Makefile.in @@ -44,7 +44,7 @@ ns_check_file = @ns_appdir@/@ns_check_file@ .PHONY: all -all: ${ns_appdir} ${ns_appbindir}/Emacs +all: ${ns_appdir} ${ns_appbindir}/Emacs ${ns_appbindir}/emacs.pdmp ${ns_check_file} ${ns_appdir}: ${srcdir}/${ns_appsrc} ${ns_appsrc} rm -rf ${ns_appdir} @@ -63,6 +63,10 @@ ${ns_appbindir}/Emacs: ${ns_appdir} ${ns_check_file} ../src/emacs${EXEEXT} ${MKDIR_P} ${ns_appbindir} cp -f ../src/emacs${EXEEXT} $@ +${ns_appbindir}/emacs.pdmp: ${ns_appdir} ${ns_check_file} ../src/emacs${EXEEXT}.pdmp + ${MKDIR_P} ${ns_appbindir} + cp -f ../src/emacs${EXEEXT}.pdmp $@ + .PHONY: FORCE ../src/emacs${EXEEXT}: FORCE

index f409ed4db2..980bd6d10e 100644

--- a/

+++ b/ diff --git a/src/Makefile.in b/src/Makefile.inindex f409ed4db2..980bd6d10e 100644--- a/ src/Makefile.in +++ b/ src/Makefile.in @@ -54,8 +54,6 @@ lwlibdir = ../lwlib # Configuration files for .o files to depend on. config_h = config.h $(srcdir)/conf_post.h -bootstrap_exe = ../src/bootstrap-emacs$(EXEEXT) - ## ns-app if HAVE_NS, else empty. OTHER_FILES = @OTHER_FILES@ @@ -332,7 +330,7 @@ BUILD_DETAILS = @BUILD_DETAILS@ UNEXEC_OBJ = @UNEXEC_OBJ@ -CANNOT_DUMP=@CANNOT_DUMP@ +DUMPING=@DUMPING@ # 'make' verbosity. AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ @@ -357,6 +355,15 @@ am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = +bootstrap_exe = ../src/bootstrap-emacs$(EXEEXT) +ifeq ($(DUMPING),pdumper) +bootstrap_pdmp := bootstrap-emacs.pdmp # Keep in sync with loadup.el +pdmp := emacs.pdmp +else +bootstrap_pdmp := +pdmp := +endif + # Flags that might be in WARN_CFLAGS but are not valid for Objective C. NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd @@ -395,7 +402,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ bignum.o buffer.o filelock.o insdel.o marker.o \ minibuf.o fileio.o dired.o \ cmds.o casetab.o casefiddle.o indent.o search.o regex-emacs.o undo.o \ - alloc.o data.o doc.o editfns.o callint.o \ + alloc.o pdumper.o data.o doc.o editfns.o callint.o \ eval.o floatfns.o fns.o font.o print.o lread.o $(MODULES_OBJ) \ syntax.o $(UNEXEC_OBJ) bytecode.o \ process.o gnutls.o callproc.o \ @@ -446,9 +453,17 @@ FIRSTFILE_OBJ=@FIRSTFILE_OBJ@ ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj) # Must be first, before dep inclusion! -all: emacs$(EXEEXT) $(OTHER_FILES) +all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES) .PHONY: all +dmpstruct_headers=$(srcdir)/lisp.h $(srcdir)/buffer.h \ + $(srcdir)/intervals.h $(srcdir)/charset.h $(srcdir)/bignum.h +pdumper.o: dmpstruct.h +dmpstruct.h: $(srcdir)/dmpstruct.awk +dmpstruct.h: $(libsrc)/make-fingerprint$(EXEEXT) $(dmpstruct_headers) + POSIXLY_CORRECT=1 awk -f $(srcdir)/dmpstruct.awk \ + $(dmpstruct_headers) > $@ + AUTO_DEPEND = @AUTO_DEPEND@ DEPDIR = deps ifeq ($(AUTO_DEPEND),yes) @@ -511,7 +526,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \ ## and emacs (which recreates bootstrap-emacs) depends on charprop, ## in practice this rule was always run anyway. $(srcdir)/macuvs.h $(lispsource)/international/charprop.el: \ - bootstrap-emacs$(EXEEXT) FORCE + bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp) FORCE $(MAKE) -C ../admin/unidata all EMACS="../$(bootstrap_exe)" ## We require charprop.el to exist before ucs-normalize.el is @@ -542,14 +557,20 @@ ${lispintdir}/characters.elc: ${charscript:.el=.elc} emacs$(EXEEXT): temacs$(EXEEXT) \ lisp.mk $(etc)/DOC $(lisp) \ $(lispsource)/international/charprop.el ${charsets} -ifeq ($(CANNOT_DUMP),yes) - ln -f temacs$(EXEEXT) $@ -else - LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup dump +ifeq ($(DUMPING),unexec) + LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=dump ifneq ($(PAXCTL_dumped),) - $(PAXCTL_dumped) $@ + $(PAXCTL_dumped) emacs$(EXEEXT) endif - ln -f $@ bootstrap-emacs$(EXEEXT) + cp -f $@ bootstrap-emacs$(EXEEXT) +else + cp -f temacs$(EXEEXT) emacs$(EXEEXT) +endif + +ifeq ($(DUMPING),pdumper) +$(pdmp): emacs$(EXEEXT) + LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump + cp -f $@ $(bootstrap_pdmp) endif ## 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 $(LIBEGNU_ARCHIVE): $(config_h) $(MAKE) -C $(lib) all +EMACS_DEPS_PRE=$(LIBXMENU) $(ALLOBJS) +EMACS_DEPS_POST=$(LIBEGNU_ARCHIVE) $(EMACSRES) ${charsets} ${charscript} +BUILD_EMACS_PRE=$(AM_V_CCLD)$(CC) $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \ + -o $@ $(ALLOBJS) +BUILD_EMACS_POST=$(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) + +## We hash this file to generate the build fingerprint +temacs.in$(EXEEXT): $(EMACS_DEPS_PRE) fingerprint-dummy.o $(EMACS_DEPS_POST) + $(BUILD_EMACS_PRE) fingerprint-dummy.o $(BUILD_EMACS_POST) + +$(libsrc)/make-fingerprint$(EXEEXT): $(libsrc)/make-fingerprint.c $(lib)/libgnu.a + $(MAKE) -C $(libsrc) make-fingerprint$(EXEEXT) + +fingerprint.c: temacs.in$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT) + $(libsrc)/make-fingerprint$(EXEEXT) temacs.in$(EXEEXT) > fingerprint.c + ## We have to create $(etc) here because init_cmdargs tests its ## existence when setting Vinstallation_directory (FIXME?). ## This goes on to affect various things, and the emacs binary fails ## to start if Vinstallation_directory has the wrong value. -temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) \ - $(LIBEGNU_ARCHIVE) $(EMACSRES) ${charsets} ${charscript} - $(AM_V_CCLD)$(CC) $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \ - -o temacs $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) +temacs$(EXEEXT): $(EMACS_DEPS_PRE) fingerprint.o $(EMACS_DEPS_POST) + $(BUILD_EMACS_PRE) fingerprint.o $(BUILD_EMACS_POST) $(MKDIR_P) $(etc) -ifneq ($(CANNOT_DUMP),yes) +ifeq ($(DUMPING),unexec) ifneq ($(PAXCTL_notdumped),) $(PAXCTL_notdumped) $@ endif @@ -638,7 +673,7 @@ emacs.res: FORCE $(MAKE) -C ../nt ../src/emacs.res .PHONY: ns-app -ns-app: emacs$(EXEEXT) +ns-app: emacs$(EXEEXT) $(pdmp) $(MAKE) -C ../nextstep all .PHONY: mostlyclean clean bootstrap-clean distclean maintainer-clean @@ -646,8 +681,11 @@ ns-app: emacs$(EXEEXT) mostlyclean: rm -f temacs$(EXEEXT) core ./*.core \#* ./*.o + rm -f temacs.in$(EXEEXT) fingerprint.c dmpstruct.h + rm -f emacs.pdmp rm -f ../etc/DOC - rm -f bootstrap-emacs$(EXEEXT) emacs-$(version)$(EXEEXT) + rm -f bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp) + rm -f emacs-$(version)$(EXEEXT) rm -f buildobj.h rm -f globals.h gl-stamp rm -f ./*.res ./*.tmp @@ -732,7 +770,7 @@ tags: TAGS ../lisp/TAGS $(lwlibdir)/TAGS ## but now that we require GNU make, we can simply specify ## bootstrap-emacs$(EXEEXT) as an order-only prerequisite. -%.elc: %.el | bootstrap-emacs$(EXEEXT) +%.elc: %.el | bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp) @$(MAKE) -C ../lisp EMACS="$(bootstrap_exe)" THEFILE=$< $<c ## VCSWITNESS points to the file that holds info about the current checkout. @@ -740,24 +778,35 @@ tags: TAGS ../lisp/TAGS $(lwlibdir)/TAGS ## If empty it is ignored; the parent makefile can set it to some other value. VCSWITNESS = -$(lispsource)/loaddefs.el: $(VCSWITNESS) | bootstrap-emacs$(EXEEXT) +$(lispsource)/loaddefs.el: $(VCSWITNESS) | \ + bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp) $(MAKE) -C ../lisp autoloads EMACS="$(bootstrap_exe)" ## Dump an Emacs executable named bootstrap-emacs containing the ## files from loadup.el in source form. + bootstrap-emacs$(EXEEXT): temacs$(EXEEXT) $(MAKE) -C ../lisp update-subdirs -ifeq ($(CANNOT_DUMP),yes) - ln -f temacs$(EXEEXT) $@ -else - $(RUN_TEMACS) --batch $(BUILD_DETAILS) --load loadup bootstrap +ifeq ($(DUMPING),unexec) + $(RUN_TEMACS) --batch $(BUILD_DETAILS) -l loadup --temacs=bootstrap ifneq ($(PAXCTL_dumped),) $(PAXCTL_dumped) emacs$(EXEEXT) endif - mv -f emacs$(EXEEXT) $@ + mv -f emacs$(EXEEXT) bootstrap-emacs$(EXEEXT) + @: Compile some files earlier to speed up further compilation. + $(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)" +else + @: In the pdumper case, make compile-first after the dump + cp -f temacs$(EXEEXT) bootstrap-emacs$(EXEEXT) endif + +ifeq ($(DUMPING),pdumper) +$(bootstrap_pdmp): bootstrap-emacs$(EXEEXT) + rm -f $@ + $(RUN_TEMACS) --batch $(BUILD_DETAILS) -l loadup --temacs=pbootstrap @: Compile some files earlier to speed up further compilation. $(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)" +endif ### Flymake support (for C only) check-syntax:

index 31e8da7016..8054aa5ae5 100644

--- a/

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

index 4d97470a28..d36c4f1f5a 100644

--- a/

+++ b/ diff --git a/src/atimer.c b/src/atimer.cindex 4d97470a28..d36c4f1f5a 100644--- a/ src/atimer.c +++ b/ src/atimer.c @@ -584,6 +584,7 @@ init_atimer (void) sigaction (SIGALRM, &action, 0); #ifdef ENABLE_CHECKING - defsubr (&Sdebug_timer_check); + if (!initialized) + defsubr (&Sdebug_timer_check); #endif }

index cc0899676d..a12c80ec0b 100644

--- a/

+++ b/ diff --git a/src/buffer.c b/src/buffer.cindex cc0899676d..a12c80ec0b 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/>. */ #include "keymap.h" #include "frame.h" #include "xwidget.h" +#include "pdumper.h" #ifdef WINDOWSNT #include "w32heap.h" /* for mmap_* */ @@ -529,6 +530,8 @@ even if it is dead. The return value is never nil. */) /* No one shows us now. */ b->window_count = 0; + memset (&b->local_flags, 0, sizeof (b->local_flags)); + BUF_GAP_SIZE (b) = 20; block_input (); /* 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. */) /* Always -1 for an indirect buffer. */ b->window_count = -1; + memset (&b->local_flags, 0, sizeof (b->local_flags)); + b->pt = b->base_buffer->pt; b->begv = b->base_buffer->begv; b->zv = b->base_buffer->zv; @@ -5001,24 +5006,37 @@ alloc_buffer_text (struct buffer *b, ptrdiff_t nbytes) void enlarge_buffer_text (struct buffer *b, ptrdiff_t delta) { - void *p; - ptrdiff_t nbytes = (BUF_Z_BYTE (b) - BUF_BEG_BYTE (b) + BUF_GAP_SIZE (b) + 1 - + delta); block_input (); + void *p; + unsigned char *old_beg = b->text->beg; + ptrdiff_t old_nbytes = + BUF_Z_BYTE (b) - BUF_BEG_BYTE (b) + BUF_GAP_SIZE (b) + 1; + ptrdiff_t new_nbytes = old_nbytes + delta; + + if (pdumper_object_p (old_beg)) + b->text->beg = NULL; + else + old_beg = NULL; + #if defined USE_MMAP_FOR_BUFFERS - p = mmap_realloc ((void **) &b->text->beg, nbytes); + p = mmap_realloc ((void **) &b->text->beg, new_nbytes); #elif defined REL_ALLOC - p = r_re_alloc ((void **) &b->text->beg, nbytes); + p = r_re_alloc ((void **) &b->text->beg, new_nbytes); #else - p = xrealloc (b->text->beg, nbytes); + p = xrealloc (b->text->beg, new_nbytes); #endif if (p == NULL) { + if (old_beg) + b->text->beg = old_beg; unblock_input (); - memory_full (nbytes); + memory_full (new_nbytes); } + if (old_beg) + memcpy (p, old_beg, min (old_nbytes, new_nbytes)); + BUF_BEG_ADDR (b) = p; unblock_input (); } @@ -5031,13 +5049,16 @@ free_buffer_text (struct buffer *b) { block_input (); + if (!pdumper_object_p (b->text->beg)) + { #if defined USE_MMAP_FOR_BUFFERS - mmap_free ((void **) &b->text->beg); + mmap_free ((void **) &b->text->beg); #elif defined REL_ALLOC - r_alloc_free ((void **) &b->text->beg); + r_alloc_free ((void **) &b->text->beg); #else - xfree (b->text->beg); + xfree (b->text->beg); #endif + } BUF_BEG_ADDR (b) = NULL; unblock_input (); @@ -5048,14 +5069,25 @@ free_buffer_text (struct buffer *b) /*********************************************************************** Initialization ***********************************************************************/ - void init_buffer_once (void) { + /* TODO: clean up the buffer-local machinery. Right now, + we have: + + buffer_defaults: default values of buffer-locals + buffer_local_flags: metadata + buffer_permanent_local_flags: metadata + buffer_local_symbols: metadata + + There must be a simpler way to store the metadata. + */ + int idx; /* Items flagged permanent get an explicit permanent-local property added in bindings.el, for clarity. */ + PDUMPER_REMEMBER_SCALAR (buffer_permanent_local_flags); memset (buffer_permanent_local_flags, 0, sizeof buffer_permanent_local_flags); /* 0 means not a lisp var, -1 means always local, else mask. */ @@ -5144,10 +5176,15 @@ init_buffer_once (void) XSETFASTINT (BVAR (&buffer_local_flags, extra_line_spacing), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, cursor_in_non_selected_windows), idx); ++idx; + /* buffer_local_flags contains no pointers, so it's safe to treat it + as a blob for pdumper. */ + PDUMPER_REMEMBER_SCALAR (buffer_local_flags); + /* Need more room? */ if (idx >= MAX_PER_BUFFER_VARS) emacs_abort (); last_per_buffer_idx = idx; + PDUMPER_REMEMBER_SCALAR (last_per_buffer_idx); /* Make sure all markable slots in buffer_defaults are initialized reasonably, so mark_buffer won't choke. */ @@ -5242,7 +5279,9 @@ init_buffer_once (void) Vbuffer_alist = Qnil; current_buffer = 0; + pdumper_remember_lv_ptr_raw (¤t_buffer, Lisp_Vectorlike); all_buffers = 0; + pdumper_remember_lv_ptr_raw (&all_buffers, Lisp_Vectorlike); QSFundamental = build_pure_c_string ("Fundamental"); @@ -5266,12 +5305,12 @@ init_buffer_once (void) } void -init_buffer (int initialized) +init_buffer (void) { Lisp_Object temp; #ifdef USE_MMAP_FOR_BUFFERS - if (initialized) + if (dumped_with_unexec_p ()) { struct buffer *b; @@ -5312,9 +5351,6 @@ init_buffer (int initialized) eassert (b->text->beg != NULL); } } -#else /* not USE_MMAP_FOR_BUFFERS */ - /* Avoid compiler warnings. */ - (void) initialized; #endif /* USE_MMAP_FOR_BUFFERS */ AUTO_STRING (scratch, "*scratch*");

index bb7d796bac..40977799bf 100644

--- a/

+++ b/ diff --git a/src/bytecode.c b/src/bytecode.cindex bb7d796bac..40977799bf 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, search as the jump table. */ Lisp_Object jmp_table = POP; if (BYTE_CODE_SAFE && !HASH_TABLE_P (jmp_table)) - emacs_abort (); + emacs_abort (); Lisp_Object v1 = POP; ptrdiff_t i; struct Lisp_Hash_Table *h = XHASH_TABLE (jmp_table); + hash_rehash_if_needed (h); /* h->count is a faster approximation for HASH_TABLE_SIZE (h) here. */

index 0911c49ae5..ba6e3350a5 100644

--- a/

+++ b/ diff --git a/src/callint.c b/src/callint.cindex 0911c49ae5..ba6e3350a5 100644--- a/ src/callint.c +++ b/ src/callint.c @@ -818,7 +818,8 @@ syms_of_callint (void) intern_c_string ("region-beginning"), intern_c_string ("region-end"), intern_c_string ("point"), - intern_c_string ("mark")); + intern_c_string ("mark")); + staticpro (&preserved_fns); DEFSYM (Qlist, "list"); DEFSYM (Qlet, "let");

index 19882e60fa..d4558387cf 100644

--- a/

+++ b/ diff --git a/src/callproc.c b/src/callproc.cindex 19882e60fa..d4558387cf 100644--- a/ src/callproc.c +++ b/ src/callproc.c @@ -1588,9 +1588,7 @@ init_callproc (void) } } -#ifndef CANNOT_DUMP - if (initialized) -#endif + if (!will_dump_p ()) { tempdir = Fdirectory_file_name (Vexec_directory); if (! file_accessible_directory_p (tempdir))

index c504d2d992..132fae9d40 100644

--- a/

+++ b/ diff --git a/src/category.c b/src/category.cindex c504d2d992..132fae9d40 100644--- a/ src/category.c +++ b/ src/category.c @@ -42,15 +42,6 @@ bset_category_table (struct buffer *b, Lisp_Object val) b->category_table_ = val; } -/* The version number of the latest category table. Each category - table has a unique version number. It is assigned a new number - also when it is modified. When a regular expression is compiled - into the struct re_pattern_buffer, the version number of the - category table (of the current buffer) at that moment is also - embedded in the structure. - - For the moment, we are not using this feature. */ -static int category_table_version; /* Category set staff. */ @@ -512,6 +503,4 @@ See the documentation of the variable `word-combining-categories'. */); defsubr (&Schar_category_set); defsubr (&Scategory_set_mnemonics); defsubr (&Smodify_category_entry); - - category_table_version = 0; }

index 724b35536e..28f6203a66 100644

--- a/

+++ b/ diff --git a/src/charset.c b/src/charset.cindex 724b35536e..28f6203a66 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/>. */ #include "coding.h" #include "buffer.h" #include "sysstdio.h" +#include "pdumper.h" /*** GENERAL NOTES on CODED CHARACTER SETS (CHARSETS) *** @@ -61,9 +62,8 @@ Lisp_Object Vcharset_hash_table; /* Table of struct charset. */ struct charset *charset_table; - -static ptrdiff_t charset_table_size; -static int charset_table_used; +ptrdiff_t charset_table_size; +int charset_table_used; /* Special charsets corresponding to symbols. */ int charset_ascii; @@ -851,6 +851,8 @@ usage: (define-charset-internal ...) */) bool new_definition_p; int nchars; + memset (&charset, 0, sizeof (charset)); + if (nargs != charset_arg_max) Fsignal (Qwrong_number_of_arguments, Fcons (intern ("define-charset-internal"), @@ -1142,9 +1144,9 @@ usage: (define-charset-internal ...) */) struct charset *new_table = xpalloc (0, &new_size, 1, min (INT_MAX, MOST_POSITIVE_FIXNUM), - sizeof *charset_table); - memcpy (new_table, charset_table, old_size * sizeof *new_table); - charset_table = new_table; + sizeof *charset_table); + memcpy (new_table, charset_table, old_size * sizeof *new_table); + charset_table = new_table; charset_table_size = new_size; /* FIXME: This leaks memory, as the old charset_table becomes unreachable. If the old charset table is charset_table_init @@ -2316,15 +2318,26 @@ init_charset_once (void) for (i = 0; i < ISO_MAX_DIMENSION; i++) for (j = 0; j < ISO_MAX_CHARS; j++) for (k = 0; k < ISO_MAX_FINAL; k++) - iso_charset_table[i][j][k] = -1; + iso_charset_table[i][j][k] = -1; + + PDUMPER_REMEMBER_SCALAR (iso_charset_table); for (i = 0; i < 256; i++) emacs_mule_charset[i] = -1; + PDUMPER_REMEMBER_SCALAR (emacs_mule_charset); + charset_jisx0201_roman = -1; + PDUMPER_REMEMBER_SCALAR (charset_jisx0201_roman); + charset_jisx0208_1978 = -1; + PDUMPER_REMEMBER_SCALAR (charset_jisx0208_1978); + charset_jisx0208 = -1; + PDUMPER_REMEMBER_SCALAR (charset_jisx0208); + charset_ksc5601 = -1; + PDUMPER_REMEMBER_SCALAR (charset_ksc5601); } /* Allocate an initial charset table that is large enough to handle @@ -2365,7 +2378,9 @@ syms_of_charset (void) charset_table = charset_table_init; charset_table_size = ARRAYELTS (charset_table_init); + PDUMPER_REMEMBER_SCALAR (charset_table_size); charset_table_used = 0; + PDUMPER_REMEMBER_SCALAR (charset_table_used); defsubr (&Scharsetp); defsubr (&Smap_charset_chars); @@ -2411,19 +2426,30 @@ the value may be a list of mnemonics. */); charset_ascii = define_charset_internal (Qascii, 1, "\x00\x7F\0\0\0\0\0", - 0, 127, 'B', -1, 0, 1, 0, 0); + 0, 127, 'B', -1, 0, 1, 0, 0); + PDUMPER_REMEMBER_SCALAR (charset_ascii); + charset_iso_8859_1 = define_charset_internal (Qiso_8859_1, 1, "\x00\xFF\0\0\0\0\0", - 0, 255, -1, -1, -1, 1, 0, 0); + 0, 255, -1, -1, -1, 1, 0, 0); + PDUMPER_REMEMBER_SCALAR (charset_iso_8859_1); + charset_unicode = define_charset_internal (Qunicode, 3, "\x00\xFF\x00\xFF\x00\x10\0", - 0, MAX_UNICODE_CHAR, -1, 0, -1, 1, 0, 0); + 0, MAX_UNICODE_CHAR, -1, 0, -1, 1, 0, 0); + PDUMPER_REMEMBER_SCALAR (charset_unicode); + charset_emacs = define_charset_internal (Qemacs, 3, "\x00\xFF\x00\xFF\x00\x3F\0", - 0, MAX_5_BYTE_CHAR, -1, 0, -1, 1, 1, 0); + 0, MAX_5_BYTE_CHAR, -1, 0, -1, 1, 1, 0); + PDUMPER_REMEMBER_SCALAR (charset_emacs); + charset_eight_bit = define_charset_internal (Qeight_bit, 1, "\x80\xFF\0\0\0\0\0", 128, 255, -1, 0, -1, 0, 1, - MAX_5_BYTE_CHAR + 1); + MAX_5_BYTE_CHAR + 1); + PDUMPER_REMEMBER_SCALAR (charset_eight_bit); + charset_unibyte = charset_iso_8859_1; + PDUMPER_REMEMBER_SCALAR (charset_unibyte); }

index 0822f2d12f..f4bed558cf 100644

--- a/

+++ b/ diff --git a/src/charset.h b/src/charset.hindex 0822f2d12f..f4bed558cf 100644--- a/ src/charset.h +++ b/ src/charset.h @@ -248,6 +248,8 @@ extern Lisp_Object Vcharset_hash_table; /* Table of struct charset. */ extern struct charset *charset_table; +extern ptrdiff_t charset_table_size; +extern int charset_table_used; #define CHARSET_FROM_ID(id) (charset_table + (id))

index 1c1462198c..665aefa34c 100644

--- a/

+++ b/ diff --git a/src/coding.c b/src/coding.cindex 1c1462198c..665aefa34c 100644--- a/ src/coding.c +++ b/ src/coding.c @@ -298,6 +298,7 @@ encode_coding_XXX (struct coding_system *coding) #include "composite.h" #include "coding.h" #include "termhooks.h" +#include "pdumper.h" Lisp_Object Vcoding_system_hash_table; @@ -10737,6 +10738,9 @@ init_coding_once (void) coding_priorities[i] = i; } + PDUMPER_REMEMBER_SCALAR (coding_categories); + PDUMPER_REMEMBER_SCALAR (coding_priorities); + /* ISO2022 specific initialize routine. */ for (i = 0; i < 0x20; i++) iso_code_class[i] = ISO_control_0; @@ -10756,6 +10760,8 @@ init_coding_once (void) iso_code_class[ISO_CODE_SS3] = ISO_single_shift_3; iso_code_class[ISO_CODE_CSI] = ISO_control_sequence_introducer; + PDUMPER_REMEMBER_SCALAR (iso_code_class); + for (i = 0; i < 256; i++) { emacs_mule_bytes[i] = 1; @@ -10764,6 +10770,8 @@ init_coding_once (void) emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_12] = 3; emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_21] = 4; emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_22] = 4; + + PDUMPER_REMEMBER_SCALAR (emacs_mule_bytes); } void @@ -10785,6 +10793,7 @@ syms_of_coding (void) Vcode_conversion_workbuf_name = build_pure_c_string (" *code-conversion-work*"); reused_workbuf_in_use = 0; + PDUMPER_REMEMBER_SCALAR (reused_workbuf_in_use); DEFSYM (Qcharset, "charset"); DEFSYM (Qtarget_idx, "target-idx");

index cd8364a293..c426cbb124 100644

--- a/

+++ b/ diff --git a/src/composite.c b/src/composite.cindex cd8364a293..c426cbb124 100644--- a/ src/composite.c +++ b/ src/composite.c @@ -654,6 +654,7 @@ Lisp_Object composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len) { struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table); + hash_rehash_if_needed (h); Lisp_Object header = LGSTRING_HEADER (gstring); EMACS_UINT hash = h->test.hashfn (&h->test, header); if (len < 0)

index 002ef6c65b..125dbf0152 100644

--- a/

+++ b/ diff --git a/src/conf_post.h b/src/conf_post.hindex 002ef6c65b..125dbf0152 100644--- a/ src/conf_post.h +++ b/ src/conf_post.h @@ -299,8 +299,10 @@ extern int emacs_setenv_TZ (char const *); #if 3 <= __GNUC__ # define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +# define ATTRIBUTE_SECTION(name) __attribute__((section (name))) #else # define ATTRIBUTE_MALLOC +#define ATTRIBUTE_SECTION(name) #endif #if __has_attribute (alloc_size)

index a9908a34f4..92a1062280 100644

--- a/

+++ b/ diff --git a/src/data.c b/src/data.cindex a9908a34f4..92a1062280 100644--- a/ src/data.c +++ b/ src/data.c @@ -804,7 +804,7 @@ The return value is undefined. */) { bool autoload = AUTOLOADP (definition); - if (NILP (Vpurify_flag) || !autoload) + if (!will_dump_p () || !autoload) { /* Only add autoload entries after dumping, because the ones before are not useful and else we get loads of them from the loaddefs.el. */ @@ -1826,7 +1826,7 @@ The function `default-value' gets the default value and `set-default' sets it. { struct Lisp_Symbol *sym; struct Lisp_Buffer_Local_Value *blv = NULL; - union Lisp_Val_Fwd valcontents; + union Lisp_Val_Fwd valcontents UNINIT; bool forwarded UNINIT; CHECK_SYMBOL (variable); @@ -1893,7 +1893,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) { Lisp_Object tem; bool forwarded UNINIT; - union Lisp_Val_Fwd valcontents; + union Lisp_Val_Fwd valcontents UNINIT; struct Lisp_Symbol *sym; struct Lisp_Buffer_Local_Value *blv = NULL; @@ -2958,7 +2958,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args, /* Set ACCUM to the next operation's result if it fits, else exit the loop. */ bool overflow = false; - intmax_t a; + intmax_t a UNINIT; switch (code) { case Aadd : overflow = INT_ADD_WRAPV (accum, next, &a); break;

index e1c4eda76e..0afae6b05a 100644

--- a/

+++ b/ diff --git a/src/dbusbind.c b/src/dbusbind.cindex e1c4eda76e..0afae6b05a 100644--- a/ src/dbusbind.c +++ b/ src/dbusbind.c @@ -1831,6 +1831,8 @@ be called when the D-Bus reply message arrives. */); xd_registered_buses = Qnil; staticpro (&xd_registered_buses); + // TODO: reset buses on dump load + Fprovide (intern_c_string ("dbusbind"), Qnil); }

index 55cdaf5de8..88783cd5da 100644

--- a/

+++ b/ diff --git a/src/dispnew.c b/src/dispnew.cindex 55cdaf5de8..88783cd5da 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/>. */ #include "systime.h" #include "tparam.h" #include "xwidget.h" +#include "pdumper.h" #ifdef HAVE_WINDOW_SYSTEM #include TERM_HEADER @@ -5987,12 +5988,24 @@ pass nil for VARIABLE. */) Initialization ***********************************************************************/ +static void +init_faces_initial (void) +{ + /* For the initial frame, we don't have any way of knowing what + are the foreground and background colors of the terminal. */ + struct frame *sf = SELECTED_FRAME (); + + FRAME_FOREGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_FG_COLOR; + FRAME_BACKGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_BG_COLOR; + call0 (intern ("tty-set-up-initial-frame-faces")); +} + /* Initialization done when Emacs fork is started, before doing stty. Determine terminal type and set terminal_driver. Then invoke its decoding routine to set up variables in the terminal package. */ -void -init_display (void) +static void +init_display_interactive (void) { char *terminal_type; @@ -6012,9 +6025,7 @@ init_display (void) with. Otherwise newly opened tty frames will not resize automatically. */ #ifdef SIGWINCH -#ifndef CANNOT_DUMP - if (initialized) -#endif /* CANNOT_DUMP */ + if (!will_dump_p ()) { struct sigaction action; emacs_sigaction_init (&action, deliver_window_change_signal); @@ -6078,11 +6089,7 @@ init_display (void) #endif /* HAVE_NTGUI */ #ifdef HAVE_NS - if (!inhibit_window_system -#ifndef CANNOT_DUMP - && initialized -#endif - ) + if (!inhibit_window_system && !will_dump_p ()) { Vinitial_window_system = Qns; Vwindow_system_version = make_fixnum (10); @@ -6170,22 +6177,23 @@ init_display (void) calculate_costs (XFRAME (selected_frame)); - /* Set up faces of the initial terminal frame of a dumped Emacs. */ - if (initialized - && !noninteractive - && NILP (Vinitial_window_system)) - { - /* For the initial frame, we don't have any way of knowing what - are the foreground and background colors of the terminal. */ - struct frame *sf = SELECTED_FRAME (); + /* Set up faces of the initial terminal frame. */ + if (!noninteractive && NILP (Vinitial_window_system)) + init_faces_initial (); +} - FRAME_FOREGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_FG_COLOR; - FRAME_BACKGROUND_PIXEL (sf) = FACE_TTY_DEFAULT_BG_COLOR; - call0 (intern ("tty-set-up-initial-frame-faces")); +void +init_display (void) +{ + if (noninteractive) + { + if (dumped_with_pdumper_p ()) + init_faces_initial (); } + else + init_display_interactive (); } - /*********************************************************************** Blinking cursor @@ -6220,6 +6228,8 @@ WINDOW nil or omitted means report on the selected window. */) Initialization ***********************************************************************/ +static void syms_of_display_for_pdumper (void); + void syms_of_display (void) { @@ -6327,11 +6337,12 @@ See `buffer-display-table' for more information. */); beginning of the next redisplay). */ redisplay_dont_pause = true; -#ifdef CANNOT_DUMP - if (noninteractive) -#endif - { - Vinitial_window_system = Qnil; - Vwindow_system_version = Qnil; - } + pdumper_do_now_and_after_load (syms_of_display_for_pdumper); +} + +static void +syms_of_display_for_pdumper (void) +{ + Vinitial_window_system = Qnil; + Vwindow_system_version = Qnil; }

new file mode 100755

index 0000000000..d222d117e6

--- /dev/null

+++ b/ diff --git a/src/dmpstruct.awk b/src/dmpstruct.awknew file mode 100755index 0000000000..d222d117e6--- /dev/null+++ b/ src/dmpstruct.awk @@ -0,0 +1,28 @@ +BEGIN { + print "/* Generated by dmpstruct.awk */" + print "#ifndef EMACS_DMPSTRUCT_H" + print "#define EMACS_DMPSTRUCT_H" + struct_name = "" + tmpfile = "dmpstruct.tmp" +} +# Match a type followed by optional syntactic whitespace +/^(enum|struct|union) [a-zA-Z0-9_]+([\t ]|\/\*.*\*\/)*$/ { + struct_name = $2 + close (tmpfile) +} +/^(enum|struct|union) [a-zA-Z0-9_]+([\t ]|\/\*.*\*\/)*$/, /^( )?};$/ { + print $0 > tmpfile +} +/^( )?} *(GCALIGNED_STRUCT)? *;$/ { + if (struct_name != "") { + fflush (tmpfile) + cmd = "../lib-src/make-fingerprint -r " tmpfile + cmd | getline hash + close (cmd) + printf "#define HASH_%s_%.10s

", struct_name, hash + struct_name = "" + } +} +END { + print "#endif /* EMACS_DMPSTRUCT_H */" +}

index 04370f7cc6..3e43d6db06 100644

--- a/

+++ b/ diff --git a/src/doc.c b/src/doc.cindex 04370f7cc6..3e43d6db06 100644--- a/ src/doc.c +++ b/ src/doc.c @@ -118,17 +118,15 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) Lisp_Object docdir = NILP (tem) ? ENCODE_FILE (Vdoc_directory) : empty_unibyte_string; ptrdiff_t docdir_sizemax = SBYTES (docdir) + 1; -#ifndef CANNOT_DUMP - docdir_sizemax = max (docdir_sizemax, sizeof sibling_etc); -#endif + if (will_dump_p ()) + docdir_sizemax = max (docdir_sizemax, sizeof sibling_etc); name = SAFE_ALLOCA (docdir_sizemax + SBYTES (file)); lispstpcpy (lispstpcpy (name, docdir), file); fd = emacs_open (name, O_RDONLY, 0); if (fd < 0) { -#ifndef CANNOT_DUMP - if (!NILP (Vpurify_flag)) + if (will_dump_p ()) { /* Preparing to dump; DOC file is probably not installed. So check in ../etc. */ @@ -136,7 +134,6 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) fd = emacs_open (name, O_RDONLY, 0); } -#endif if (fd < 0) { if (errno == EMFILE || errno == ENFILE) @@ -545,12 +542,7 @@ the same file name is found in the `doc-directory'. */) CHECK_STRING (filename); - if -#ifndef CANNOT_DUMP - (!NILP (Vpurify_flag)) -#else /* CANNOT_DUMP */ - (0) -#endif /* CANNOT_DUMP */ + if (will_dump_p ()) { dirname = sibling_etc; dirlen = sizeof sibling_etc - 1;

index 55127011d8..01376b0637 100644

--- a/

+++ b/ diff --git a/src/editfns.c b/src/editfns.cindex 55127011d8..01376b0637 100644--- a/ src/editfns.c +++ b/ src/editfns.c @@ -3454,7 +3454,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) bool format_as_long_double = false; double darg; - long double ldarg; + long double ldarg UNINIT; if (FLOATP (arg)) darg = XFLOAT_DATA (arg);

index e695a3d2e6..cbab023420 100644

--- a/

+++ b/ diff --git a/src/emacs-module.c b/src/emacs-module.cindex e695a3d2e6..cbab023420 100644--- a/ src/emacs-module.c +++ b/ src/emacs-module.c @@ -1191,7 +1191,10 @@ void syms_of_module (void) { if (!plain_values) - ltv_mark = Fcons (Qnil, Qnil); + { + ltv_mark = Fcons (Qnil, Qnil); + staticpro (<v_mark); + } eassert (NILP (value_to_lisp (module_nil))); DEFSYM (Qmodule_refs_hash, "module-refs-hash");

index 221b074afc..9c88b6e3f1 100644

--- a/

+++ b/ diff --git a/src/emacs.c b/src/emacs.cindex 221b074afc..9c88b6e3f1 100644--- a/ src/emacs.c +++ b/ src/emacs.c @@ -118,6 +118,9 @@ extern char etext; #include <sys/resource.h> #endif +#include "pdumper.h" +#include "epaths.h" + static const char emacs_version[] = PACKAGE_VERSION; static const char emacs_copyright[] = COPYRIGHT; static const char emacs_bugreport[] = PACKAGE_BUGREPORT; @@ -130,19 +133,9 @@ Lisp_Object empty_unibyte_string, empty_multibyte_string; Lisp_Object Vlibrary_cache; #endif -/* Set after Emacs has started up the first time. - Prevents reinitialization of the Lisp world and keymaps - on subsequent starts. */ +struct gflags gflags; bool initialized; -#ifndef CANNOT_DUMP -/* Set to true if this instance of Emacs might dump. */ -# ifndef DOUG_LEA_MALLOC -static -# endif -bool might_dump; -#endif - /* If true, Emacs should not attempt to use a window-specific code, but instead should use the virtual terminal under which it was started. */ bool inhibit_window_system; @@ -519,8 +512,7 @@ init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd) etc_exists = Ffile_exists_p (tem); if (!NILP (etc_exists)) { - Vinstallation_directory - = Ffile_name_as_directory (dir); + Vinstallation_directory = Ffile_name_as_directory (dir); break; } } @@ -545,8 +537,7 @@ init_cmdargs (int argc, char **argv, int skip_args, char const *original_pwd) if (!NILP (etc_exists)) { tem = Fexpand_file_name (build_string (".."), dir); - Vinstallation_directory - = Ffile_name_as_directory (tem); + Vinstallation_directory = Ffile_name_as_directory (tem); break; } } @@ -659,6 +650,43 @@ argmatch (char **argv, int argc, const char *sstr, const char *lstr, } } +static bool +string_starts_with_p (const char* string, const char* prefix) +{ + return strncmp (string, prefix, strlen (prefix)) == 0; +} + +/* Return the value of GNU-style long argument ARGUMENT if given on + command line. ARGUMENT must begin with "-". If ARGUMENT is not + given, return NULL. */ +static char * +find_argument (const char *argument, int argc, char **argv) +{ + char *found = NULL; + int i; + + eassert (argument[0] == '-'); + + for (i = 1; i < argc; ++i) + if (string_starts_with_p (argv[i], argument) && + ((argv[i] + strlen (argument))[0] == '=' || + (argv[i] + strlen (argument))[0] == '\0')) + { + int j = i; + found = argv[j++] + strlen (argument); + if (*found == '=') + ++found; + else if (i < argc) + found = argv[j++]; + else + fatal ("no argument given for %s", argument); + break; + } + else if (strcmp (argv[i], "--") == 0) + break; + return found; +} + /* Close standard output and standard error, reporting any write errors as best we can. This is intended for use with atexit. */ static void @@ -677,6 +705,114 @@ close_output_streams (void) _exit (EXIT_FAILURE); } +#ifdef HAVE_PDUMPER + +static const char * +dump_error_to_string (enum pdumper_load_result result) +{ + switch (result) + { + case PDUMPER_LOAD_SUCCESS: + return "success"; + case PDUMPER_LOAD_OOM: + return "out of memory"; + case PDUMPER_NOT_LOADED: + return "not loaded"; + case PDUMPER_LOAD_FILE_NOT_FOUND: + return "could not open file"; + case PDUMPER_LOAD_BAD_FILE_TYPE: + return "not a dump file"; + case PDUMPER_LOAD_FAILED_DUMP: + return "dump file is result of failed dump attempt"; + case PDUMPER_LO