summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--admin/notes/big-elc313
-rw-r--r--configure.ac11
-rw-r--r--lisp/emacs-lisp/cl-lib.el4
-rw-r--r--lisp/emacs-lisp/cl-macs.el1
-rw-r--r--lisp/emacs-lisp/macroexp.el3
-rw-r--r--lisp/frame.el2
-rw-r--r--lisp/international/mule.el4
-rw-r--r--lisp/loadup.el383
-rw-r--r--lisp/progmodes/elisp-mode.el22
-rw-r--r--src/Makefile.in4
-rw-r--r--src/alloc.c2
-rw-r--r--src/charset.c2
-rw-r--r--src/coding.c8
-rw-r--r--src/doc.c66
-rw-r--r--src/emacs.c37
-rw-r--r--src/print.c52
-rw-r--r--src/syntax.c13
-rw-r--r--src/unexw32.c2
-rw-r--r--src/xfaces.c7
19 files changed, 824 insertions, 112 deletions
diff --git a/admin/notes/big-elc b/admin/notes/big-elc
new file mode 100644
index 00000000000..c63e84da731
--- /dev/null
+++ b/admin/notes/big-elc
@@ -0,0 +1,313 @@
+“Big elc file” startup approach -*- mode: org; coding: utf-8 -*-
+
+These notes discuss the design and implementation status of the “big
+elc file” approach for saving and loading the Lisp environment.
+
+* Justification
+
+The original discussion in which the idea arose was on the possible
+elimination of the “unexec” mechanism, which is troublesome to
+maintain.
+
+The CANNOT_DUMP support, when it isn’t suffering bit-rot, does allow
+for loading all of the Lisp code from scratch at startup. However,
+doing so is rather slow.
+
+Stefan Monnier suggested (and implemented) loading the Lisp
+environment via loadup.el, as we do now in the “unexec” world, and
+writing out a single Lisp file with all of the resulting function and
+variable settings in it. Then a normal Emacs invocation can load this
+one Lisp file, instead of dozens, and complex data structures can
+simply be read, instead of constructed at run time.
+
+It turned out to be desirable for a couple of others to be loaded at
+run time as well, but the one big file loads most of the settings.
+
+* Implementation
+
+** Saving the Lisp environment
+
+In loadup.el, we iterate over the obarray, collecting names of faces
+and coding systems and such for later processing. Each symbol’s
+function, variable, and property values get turned into the
+appropriate fset, set-default, or setplist calls. Calls to defvar and
+make-variable-buffer-local may be generated as well. The resulting
+forms are all emitted as part of one large “progn” form, so that the
+print-circle support can correctly cross-link references to objects in
+a way that the reader will reconstruct.
+
+A few variables are explicitly skipped because they’re in use during
+the read process, or they’re intended to be reinitialized when emacs
+starts up. Some others are skipped for now because they’re not
+printable objects.
+
+Most of the support for the unexec path is present, but ignored or
+commented out. This keeps diffs (and merging) simpler.
+
+*** charsets, coding systems, and faces
+
+Some changes to charset and coding system support were made so that
+when a definition is created for a new name, a property gets attached
+to the symbol with the relevant parameters so that we can write out
+enough information to reconstruct the definition after reading it
+back.
+
+After the main definitions are written out, we emit additional forms
+to fix up charset definitions, face specs, and so on. These don’t
+have to worry about cross-linked data structures, so breaking them out
+into separate forms keeps things simpler.
+
+*** deferred loading
+
+The standard category table is huge if written out, so we load
+international/characters indirectly via dumped.elc instead. We could
+perhaps suppress the variables and functions defined in
+international/characters from being output with the rest of the Lisp
+environment. That information should be available via the load
+history. We would be assuming that no other loaded Lisp code alters
+the variables’ values; any modified function values will be overridden
+by the defalias calls.
+
+Advice attached to a subr can’t be written out and read back in
+because of the “#<subr...>” syntax; uniquify attaches advice to
+rename-buffer, so loading of uniquify is deferred until loading
+dumped.elc, or until we’ve determined that we’re not dumping at all.
+
+*** efficient symbol reading
+
+The symbol parser is not terribly fast. It reads one character at a
+time (which involves reading one or more bytes, and figuring out the
+possible encoding of a multibyte character) and figuring out where the
+end of the symbol is; then the obarray needs to be scanned to see if
+the symbol is already present.
+
+It turns out that the “#N#” processing is faster. So now there’s a
+new option to the printer that will use this form for symbols that
+show up more than once. Parsing “#24#” and doing the hash table
+lookup works out better than parsing “setplist” and scanning the
+obarray over and over, though it makes it much harder for a human to
+read.
+
+** Loading the Lisp environment
+
+The default action to invoke on startup is now to load
+“../src/dumped.elc”. For experimentation that name works fine, but
+for installation it’ll probably be something like just “dumped.elc”,
+found via the load path.
+
+New primitives are needed to deal with Emacs data that is not purely
+Lisp data structures:
+
+ + internal--set-standard-syntax-table
+ + define-charset-internal
+ + define-coding-system-internal
+
+*** Speeding up the reader
+
+Reading a very large Lisp file (over a couple of megabytes) is still
+slow.
+
+While it seems unavoidable that loading a Lisp environment at run time
+will be at least slightly slower than having that environment be part
+of the executable image when the process is launched, we want to keep
+the process startup time acceptably fast. (No, that’s not a precisely
+defined goal.)
+
+So, a few changes have been made to speed up reading the large Lisp
+file. Some of them may be generally applicable, even if the
+big-elc-file approach isn’t adopted. Others may be too specific to
+this use case to warrant the additional code.
+
+ + Avoiding substitution recursion for #N# forms when the new object
+ is a cons cell.
+ + Using hash tables instead of lists for forms to substitute.
+ + Avoiding circular object checks in some cases.
+ + Handle substituting into a list iteratively instead of
+ recursively. (This one was more about making performance analysis
+ easier for certain tools than directly improving performance.)
+ + Special-case reading from a file. Avoid repeated checks of the
+ type of input source and associated dispatching to appropriate
+ support routines, and hard-code the file-based calls. Streamline
+ the input blocking and unblocking.
+ + Avoid string allocation when reading symbols already in the
+ obarray.
+
+* Open Issues
+
+** CANNOT_DUMP, purify-flag
+
+The branch has been rebased onto a recent enough “master” version that
+CANNOT_DUMP works fairly well on GNU/Linux systems. The branch has
+now been updated to set CANNOT_DUMP unconditionally, to disable the
+unexec code. As long as dumped.elc does all the proper initialization
+like the old loadup.el did, that should work well.
+
+The regular CANNOT_DUMP build does not work on mac OS, at least in the
+otherwise-normal Nextstep, self-contained-app mode; it seems to be a
+load-path problem. See bug #27760.
+
+Some code still looks at purify-flag, including eval.c requiring that
+it be nil when autoloading. So we still let the big progn set its
+value.
+
+** Building and bootstrapping
+
+The bootstrap process assumes it needs to build the emacs executable
+twice, with different environments based on whether stuff has been
+byte-compiled.
+
+In this branch, the executables should be the same, but the dumped
+Lisp files will be different. Ideally we should build the executable
+only once, and dump out different environment files. Possibly this
+means that instead of “bootstrap-emacs” we should invoke something
+like:
+
+ ../path/to/emacs --no-loadup -l ../path/to/bootstrap-dump.elc ...
+
+It might also make sense for bootstrap-dump.elc to include the byte
+compiler, and to byte-compile the byte compiler (and other
+COMPILE_FIRST stuff) in memory before dumping.
+
+Re-examine whether the use of build numbers makes sense, if we’re not
+rewriting the executable image.
+
+** installation
+
+Installing this version of Emacs hasn’t been tested much.
+
+** offset builds (srcdir=… or /path/to/configure …)
+
+Builds outside of the source tree (where srcdir is not the root of the
+build tree) have not been tested much, and don’t currently work.
+
+The first problem, at least while bootstrapping: “../src/dumped.elc”
+is relative to $lispdir which is in the source tree, so Emacs doesn’t
+find the dumped.elc file that’s in the build tree.
+
+Moving dumped.elc under $lispdir would be inappropriate since the
+directory is in the source tree and the file content is specific to
+the configuration being built. We could create a “lisp” directory in
+the build tree and write dumped.elc there, but since we don’t
+currently have such a directory, that’ll mean some changes to the load
+path computation, which is already pretty messy.
+
+** Unhandled aspects of environment saving
+
+*** unprintable objects
+
+global-buffers-menu-map has cdr slot set to nil, but this seems to get
+fixed up at run time, so simply omitting it may be okay.
+
+advertised-signature-table has several subr entries. Perhaps we could
+filter those out, dump the rest, and then emit additional code to
+fetch the subr values via their symbol names and insert them into the
+hash after its initial creation.
+
+Markers and overlays that aren’t associated with buffers are replaced
+with newly created ones. This only works for variables with these
+objects as their values; markers or overlays contained within lists or
+elsewhere wouldn’t be fixed up, and any sharing of these objects would
+be lost, but there don’t appear to be any such cases.
+
+Any obarrays will be dumped in an incomplete form. We can’t
+distinguish them from vectors that contain symbols and zeros.
+(Possible fix someday: Make obarrays their own type.) As a special
+case of this, though, we do look for abbrev tables, and generate code
+to recreate them at load time.
+
+*** make-local-variable
+
+Different flavors of locally-bound variables are hard to distinguish
+and may not all be saved properly.
+
+*** defvaralias
+
+For variable aliases, we emit a defvaralias command and skip the
+default-value processing; we keep the property list processing and the
+rest. Is there anything else that needs to be changed?
+
+*** documentation strings
+
+We call Snarf-documentation at load time, because it’s the only way to
+get documentation pointers for Lisp subrs loaded. That may be
+addressable in other ways, but for the moment it’s outside the scope
+of this branch.
+
+Since we do call Snarf-documentation at load time, we can remove the
+doc strings in DOC from dumped.elc, but we have to be a little careful
+because not all of the pre-loaded Lisp doc strings wind up in DOC.
+The easy way to do that, of course, is to scan DOC and, for each doc
+entry we find, remove the documentation from the live Lisp data before
+dumping. So, Snarf-documentation now takes an optional argument to
+tell it to do that; that cut about 22% of the size of dumped.elc at
+the time.
+
+There are still a bunch of doc strings winding up in dumped.elc from
+various sources; see bug #27748. (Not mentioned in the bug report:
+Compiled lambda forms get “(fn N)” style doc strings in their bytecode
+representations too. But because we key on function names, there’s no
+way to accomodate them in the DOC file.)
+
+*** locations of definitions
+
+C-h v shows variables as having been defined by dumped.elc, not by the
+original source file.
+
+** coding system definitions
+
+We repeatedly iterate over coding system names, trying to reload each
+definition, and postponing those that fail. We should be able to work
+out the dependencies between them and construct an order that requires
+only one pass. (Is it worth it?)
+
+Fix coding-system-list; it seems to have duplicates now.
+
+** error reporting
+
+If dumped.elc can’t be found, Emacs will quietly exit with exit
+code 42. Unfortunately, when running in X mode, it’s difficult for
+Lisp code to print any messages to standard error when quitting. But
+we need to quit, at least in tty mode (do we in X mode?), because
+interactive usage requires some definitions provided only by the Lisp
+environment.
+
+** garbage collection
+
+The dumped .elc file contains a very large Lisp form with most of the
+definitions in it. Causing the garbage collector to always be invoked
+during startup guarantees some minimum additional delay before the
+user will be able to interact with Emacs.
+
+More clever heuristics for when to do GC are probably possible, but
+outside the scope of this branch. For now, gc-cons-threshold has been
+raised, arbitrarily, to a value that seems to allow for loading
+“dumped.elc” on GNU/Linux without GC during or immediately after.
+
+** load path setting
+
+Environment variable support may be broken.
+
+** little niceties
+
+Maybe we should rename the file, so that we display “Loading
+lisp-environment...” during startup.
+
+** bugs?
+
+The default value of charset-map-path is set based on the build tree
+(or source tree?), so reverting via customize would probably result in
+a bogus value. This bug exists in the master version as well when
+using unexec; in CANNOT_DUMP mode (when the Lisp code is only loaded
+from the installed tree) it doesn’t seem to be a problem.
+
+** other changes
+
+Dropped changes from previous revisions due to merge conflicts; may
+reinstate later:
+
+ + In lread.c, substitute in cons iteratively (on “cdr” slot) instead
+ of recursively.
+ + In lread.c, change “seen” list to hash table.
+ + In lread.c, add a separate read1 loop specialized for file reading,
+ with input blocking manipulated only when actually reading from the
+ file, not when just pulling the next byte from a buffer.
diff --git a/configure.ac b/configure.ac
index c3e440adcaa..144d6881fe6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1349,10 +1349,9 @@ AC_CACHE_CHECK([whether addresses are sanitized],
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
+dnl
+dnl For the big-elc model, we never support dumping.
+CANNOT_DUMP=yes
if test "$CANNOT_DUMP" = "yes"; then
AC_DEFINE(CANNOT_DUMP, 1, [Define if Emacs cannot be dumped on your system.])
@@ -2206,9 +2205,7 @@ system_malloc=yes
test "$CANNOT_DUMP" = yes ||
case "$opsys" in
## darwin ld insists on the use of malloc routines in the System framework.
- darwin | mingw32 | nacl | sol2-10) ;;
- cygwin) hybrid_malloc=yes
- system_malloc= ;;
+ cygwin | darwin | mingw32 | nacl | sol2-10) ;;
*) test "$ac_cv_func_sbrk" = yes && system_malloc=$emacs_cv_sanitize_address;;
esac
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el
index 6ac08d839b1..15622b3384e 100644
--- a/lisp/emacs-lisp/cl-lib.el
+++ b/lisp/emacs-lisp/cl-lib.el
@@ -666,8 +666,4 @@ of record objects."
(t
(advice-remove 'type-of #'cl--old-struct-type-of))))
-;; Local variables:
-;; byte-compile-dynamic: t
-;; End:
-
;;; cl-lib.el ends here
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index b1ada00f4a4..4f42d635d4b 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -3243,7 +3243,6 @@ STRUCT and SLOT-NAME are symbols. INST is a structure instance."
(run-hooks 'cl-macs-load-hook)
;; Local variables:
-;; byte-compile-dynamic: t
;; generated-autoload-file: "cl-loaddefs.el"
;; End:
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index 9bc194c478c..2285968134e 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -439,7 +439,8 @@ symbol itself."
(or (memq symbol '(nil t))
(keywordp symbol)
(if any-value
- (or (memq symbol byte-compile-const-variables)
+ (or (and (boundp 'byte-compile-const-variables)
+ (memq symbol byte-compile-const-variables))
;; FIXME: We should provide a less intrusive way to find out
;; if a variable is "constant".
(and (boundp symbol)
diff --git a/lisp/frame.el b/lisp/frame.el
index 2a14302e9fb..67b6bb53d87 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -2469,7 +2469,7 @@ See also `toggle-frame-maximized'."
;; F5 then produces the correct effect, the variable doesn't need
;; to be in this list; otherwise, it does.
(mapc (lambda (var)
- (add-variable-watcher var (symbol-function 'set-buffer-redisplay)))
+ (add-variable-watcher var 'set-buffer-redisplay))
'(line-spacing
overline-margin
line-prefix
diff --git a/lisp/international/mule.el b/lisp/international/mule.el
index 6cfb7e6d457..b6996d4b322 100644
--- a/lisp/international/mule.el
+++ b/lisp/international/mule.el
@@ -290,7 +290,7 @@ attribute."
elt))
props))
(setcdr (assq :plist attrs) props)
-
+ (put name 'internal--charset-args (mapcar #'cdr attrs))
(apply 'define-charset-internal name (mapcar 'cdr attrs))))
@@ -920,6 +920,8 @@ non-ASCII files. This attribute is meaningful only when
(cons :name (cons name (cons :docstring (cons (purecopy docstring)
props)))))
(setcdr (assq :plist common-attrs) props)
+ (put name 'internal--cs-args
+ (mapcar #'cdr (append common-attrs spec-attrs)))
(apply 'define-coding-system-internal
name (mapcar 'cdr (append common-attrs spec-attrs)))))
diff --git a/lisp/loadup.el b/lisp/loadup.el
index af42cd97111..e063ad8fc54 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -1,4 +1,4 @@
-;;; loadup.el --- load up standardly loaded Lisp files for Emacs
+;;; loadup.el --- load up standardly loaded Lisp files for Emacs -*- lexical-binding:t -*-
;; Copyright (C) 1985-1986, 1992, 1994, 2001-2017 Free Software
;; Foundation, Inc.
@@ -57,6 +57,17 @@
;; Add subdirectories to the load-path for files that might get
;; autoloaded when bootstrapping.
;; This is because PATH_DUMPLOADSEARCH is just "../lisp".
+(let ((dir (car load-path)))
+ (message "load path is %S" load-path)
+ (setq load-path (list (expand-file-name "." dir)
+ (expand-file-name "emacs-lisp" dir)
+ (expand-file-name "language" dir)
+ (expand-file-name "international" dir)
+ (expand-file-name "textmodes" dir)
+ (expand-file-name "vc" dir))))
+
+(setq purify-flag nil)
+
(if (or (equal (member "bootstrap" command-line-args) '("bootstrap"))
;; FIXME this is irritatingly fragile.
(and (stringp (nth 4 command-line-args))
@@ -64,22 +75,13 @@
(nth 4 command-line-args)))
(member (nth 7 command-line-args) '("unidata-gen-file"
"unidata-gen-charprop"))
- (if (fboundp 'dump-emacs)
+ (if t; (fboundp 'dump-emacs)
(string-match "src/bootstrap-emacs" (nth 0 command-line-args))
t))
- (let ((dir (car 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 "language" dir)
- (expand-file-name "international" dir)
- (expand-file-name "textmodes" dir)
- (expand-file-name "vc" dir)))))
+ ;; 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))
(if (eq t purify-flag)
;; Hash consing saved around 11% of pure space in my tests.
@@ -88,7 +90,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)
+(if (and t; (fboundp 'dump-emacs)
(or (equal (member "bootstrap" command-line-args) '("bootstrap"))
(equal (member "dump" command-line-args) '("dump"))))
(progn
@@ -314,9 +316,12 @@
;; Preload some constants and floating point functions.
(load "emacs-lisp/float-sup")
+(load "emacs-lisp/cl-macs")
+(load "emacs-lisp/cl-lib")
+(load "emacs-lisp/gv")
+
(load "vc/vc-hooks")
(load "vc/ediff-hook")
-(load "uniquify")
(load "electric")
(load "emacs-lisp/eldoc")
(load "cus-start") ;Late to reduce customize-rogue (needs loaddefs.el anyway)
@@ -350,14 +355,14 @@ lost after dumping")))
;; 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)
+ t; (fboundp 'dump-emacs)
(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)
+ t; (fboundp 'dump-emacs)
(not (eq system-type 'ms-dos)))
(let* ((base (concat "emacs-" emacs-version "."))
(exelen (if (eq system-type 'windows-nt) -4))
@@ -375,9 +380,9 @@ lost after dumping")))
(message "Finding pointers to doc strings...")
-(if (and (fboundp 'dump-emacs)
+(if (and t; (fboundp 'dump-emacs)
(equal (last command-line-args) '("dump")))
- (Snarf-documentation "DOC")
+ (Snarf-documentation "DOC" 'clear)
(condition-case nil
(Snarf-documentation "DOC")
(error nil)))
@@ -445,7 +450,7 @@ lost after dumping")))
;; Make sure we will attempt bidi reordering henceforth.
(setq redisplay--inhibit-bidi nil)
-(if (and (fboundp 'dump-emacs)
+(if (and t; (fboundp 'dump-emacs)
(member (car (last command-line-args)) '("dump" "bootstrap")))
(progn
;; Prevent build-time PATH getting stored in the binary.
@@ -461,29 +466,325 @@ lost after dumping")))
;; 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)
- ;; 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)))
+ ;; (dump-emacs "emacs" "temacs")
+ ;; (message "%d pure bytes used" pure-bytes-used)
+ (let ((exe (if (memq system-type '(cygwin windows-nt ms-dos)) ".exe" "")))
+ (copy-file (expand-file-name (concat "temacs" exe) invocation-directory)
+ (expand-file-name (concat "emacs" exe) invocation-directory)
+ t)
+ ;; 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)))
+ (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)))
+ (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))))
+ (message "Dumping into dumped.elc...preparing...")
+
+ ;; Dump the current state into a file so we can reload it!
+ (message "Dumping into dumped.elc...generating...")
+ (let ((faces '())
+ (coding-systems '()) (coding-system-aliases '())
+ (charsets '()) (charset-aliases '())
+ (unified-charsets '())
+ (abbrev-tables (make-hash-table :test 'eq))
+ (abbrev-assign-cmds '())
+ (abbrev-make-cmds '())
+ (abbrev-counter 0)
+ (cmds '()))
+ (setcdr global-buffers-menu-map nil) ;; Get rid of buffer objects!
+ (push `(internal--set-standard-syntax-table
+ ,(standard-syntax-table))
+ cmds)
+ (mapatoms
+ (lambda (s)
+ (when (fboundp s)
+ (if (subrp (symbol-function s))
+ ;; subr objects aren't readable!
+ (unless (equal (symbol-name s) (subr-name (symbol-function s)))
+ (push `(fset ',s (symbol-function ',(intern (subr-name (symbol-function s))))) cmds))
+ (push `(fset ',s ,(macroexp-quote (symbol-function s)))
+ cmds)))
+ (if (not (eq (indirect-variable s) s))
+ (push `(defvaralias ',s ',(indirect-variable s))
+ cmds))
+ (when (and (default-boundp s)
+ (not (macroexp--const-symbol-p s 'any-value))
+ ;; I think we don't need/want these!
+ (not (memq s '(terminal-frame obarray
+ initial-window-system window-system
+ ;; custom-delayed-init-variables
+ current-load-list
+ coding-system-list
+ internal--text-quoting-flag
+ exec-path
+ process-environment
+ initial-environment
+ exec-directory
+ data-directory
+ charset-map-path
+ source-directory
+ invocation-directory
+ load-file-name
+ doc-directory
+ load-path
+ user-full-name
+ user-login-name
+ user-real-login-name
+ system-name
+ command-line-args noninteractive
+ load-history
+ ;; Any let-bound variables during
+ ;; dump process will be useless.
+ faces coding-systems coding-system-aliases
+ charsets charset-aliases unified-charsets
+ abbrev-tables abbrev-counter
+ abbrev-make-cmds abbrev-assign-cmds
+ cmds)))
+ (eq (indirect-variable s) s))
+ (let ((v (default-value s)))
+ (push `(set-default
+ ',s
+ ,(cond
+ ;; FIXME: (Correct) hack to avoid
+ ;; unprintable objects.
+ ((eq s 'undo-auto--undoably-changed-buffers) nil)
+ ;; FIXME: Incorrect hack to avoid
+ ;; unprintable objects.
+ ((eq s 'advertised-signature-table)
+ (make-hash-table :test 'eq :weakness 'key))
+ ((subrp v)
+ `(symbol-function ',(intern (subr-name v))))
+ ((and (markerp v) (null (marker-buffer v)))
+ '(make-marker))
+ ((and (overlayp v) (null (overlay-buffer v)))
+ (let (propsets
+ (props (overlay-properties v)))
+ (while props
+ (let ((prop (car props))
+ (val (cadr props)))
+ (push `(overlay-put ol ',prop ',val) propsets)
+ (setq props (cddr props))))
+ `(let ((ol (make-overlay (point-min) (point-min))))
+ ,@propsets
+ (delete-overlay ol)
+ ol)))
+ ;; abbrev-table-p isn't very robust
+ ((condition-case nil
+ (abbrev-table-p v)
+ (error nil))
+ (cl-labels ((replace-abbrevs-for-dump
+ (table)
+ (or (abbrev-table-empty-p table)
+ (error "Non-empty abbrev tables not handled"))
+ (let ((newval (gethash table abbrev-tables)))
+ (if newval
+ `(aref scratch-abbrev-tables ,newval)
+ (let* ((props (symbol-plist (obarray-get table ""))))
+ (cond ((plist-get props :parents)
+ (setq props (copy-sequence props))
+ (plist-put props
+ :parents
+ (mapcar (lambda (value)
+ (list '\, (replace-abbrevs-for-dump value)))
+ (plist-get props :parents)))
+ (setq props (list '\` props)))
+ ((eq (length props) 2)
+ ;; Only :abbrev-table-modiff, which gets added at creation anyway.
+ (setq props nil)))
+ (push `(aset scratch-abbrev-tables
+ ,abbrev-counter
+ ,(if props
+ `(make-abbrev-table ,props)
+ '(make-abbrev-table)))
+ abbrev-make-cmds)
+ (puthash table abbrev-counter abbrev-tables)
+ (prog1
+ `(aref scratch-abbrev-tables ,abbrev-counter)
+ (setq abbrev-counter (1+ abbrev-counter))))))))
+ (push `(set-default ',s
+ ,(replace-abbrevs-for-dump v))
+ abbrev-assign-cmds))
+ ;; Placeholder to be used before we know
+ ;; we've defined make-abbrev-table.
+ 0)
+ (v (macroexp-quote v))))
+ cmds)
+ ;; Local variables: make-variable-buffer-local,
+ ;; make-local-variable, and make-variable-frame-local.
+ ;;
+ ;; We may need better introspection facilities to get
+ ;; this right. For now, assume only the first kind is
+ ;; in use during loadup.
+ (if (local-variable-if-set-p s)
+ (push `(make-variable-buffer-local ',s) cmds))
+ (if (special-variable-p s)
+ ;; A dummy initializer is needed for defvar to mark
+ ;; the variable as special.
+ (push `(defvar ,s 0) cmds))))
+ (when (symbol-plist s)
+ (push `(setplist ',s ',(symbol-plist s)) cmds))
+ (when (get s 'face-defface-spec)
+ (push s faces))
+ (if (get s 'internal--cs-args)
+ (push s coding-systems))
+ (when (and (coding-system-p s)
+ (not (eq s (car (coding-system-aliases s)))))
+ (push (cons s (car (coding-system-aliases s)))
+ coding-system-aliases))
+ (if (get s 'internal--charset-args)
+ (progn
+ (push s charsets)
+ (if (member :unify-map
+ (nth 15 (get s 'internal--charset-args)))
+ (push s unified-charsets)))
+ (when (and (charsetp s)
+ (not (eq s (get-charset-property s :name))))
+ (push (cons s (get-charset-property s :name))
+ charset-aliases))))
+ obarray)
+
+ ;; Convert preloaded file names in load-history to relative
+ (let ((simple-file-name
+ ;; Look for simple.el or simple.elc and use their directory
+ ;; as the place where all Lisp files live.
+ (locate-file "simple" load-path (get-load-suffixes)))
+ lisp-dir lisp-dir-length)
+ ;; Don't abort if simple.el cannot be found, but print a warning.
+ ;; Although in most usage we are going to cryptically abort a moment
+ ;; later anyway, due to missing required bidi data files (eg bug#13430).
+ (if (null simple-file-name)
+ (let ((standard-output 'external-debugging-output)
+ (lispdir (expand-file-name "../lisp" data-directory)))
+ (princ "Warning: Could not find simple.el or simple.elc")
+ (terpri)
+ (when (getenv "EMACSLOADPATH")
+ (princ "The EMACSLOADPATH environment variable is set, \
+please check its value")
+ (terpri))
+ (unless (file-readable-p lispdir)
+ (princ (format "Lisp directory %s not readable?" lispdir))
+ (terpri)))
+ (setq lisp-dir (file-truename (file-name-directory simple-file-name)))
+ (setq lisp-dir-length (length lisp-dir))
+ (let ((fake-load-history
+ (mapcar (lambda (elt)
+ (if (and (stringp (car elt))
+ (file-name-absolute-p (car elt))
+ (> (length (car elt)) lisp-dir-length)
+ (string-equal lisp-dir
+ (substring (car elt) 0 lisp-dir-length))
+ )
+ (cons (substring (car elt) lisp-dir-length)
+ (cdr elt))
+ elt))
+ load-history)))
+ (push `(setq load-history ',fake-load-history)
+ cmds))))
+
+ (message "Dumping into dumped.elc...printing...")
+ (with-current-buffer (generate-new-buffer "dumped.elc")
+ (setq default-directory invocation-directory)
+ (insert ";ELC\^W\^@\^@\^@\n;;; Compiled\n;;; in Emacs version "
+ emacs-version "\n")
+ (let ((print-circle t)
+ (print-gensym t)
+ (print-quoted t)
+ (print-level nil)
+ (print-length nil)
+ (print-escape-newlines t)
+ (print-symbols-as-references t)
+ (standard-output (current-buffer)))
+ (print '(setq purify-flag nil))
+ (print '(get-buffer-create "*Messages*"))
+ (print `(progn . ,cmds))
+ ;; Now that make-abbrev-table is defined, use it.
+ (print `(let ((scratch-abbrev-tables (make-vector ,abbrev-counter 0)))
+ ,@(nreverse abbrev-make-cmds)
+ ,@abbrev-assign-cmds))
+ (print `(let ((css ',charsets))
+ (dotimes (i 3)
+ (dolist (cs (prog1 css (setq css nil)))
+ ;; (message "Defining charset %S..." cs)
+ (condition-case nil
+ (progn
+ (apply #'define-charset-internal
+ cs (get cs 'internal--charset-args))
+ ;; (message "Defining charset %S...done" cs)
+ )
+ (error
+ ;; (message "Defining charset %S...postponed"
+ ;; cs)
+ (push cs css)))))))
+ (print `(dolist (cs ',charset-aliases)
+ (define-charset-alias (car cs) (cdr cs))))
+ (print `(let ((css ',coding-systems))
+ (dotimes (i 3)
+ (dolist (cs (prog1 css (setq css nil)))
+ ;; (message "Defining coding-system %S..." cs)
+ (condition-case nil
+ (progn
+ (apply #'define-coding-system-internal
+ cs (get cs 'internal--cs-args))
+ ;; (message "Defining coding-system %S...done" cs)
+ )
+ (error
+ ;; (message "Defining coding-system %S...postponed"
+ ;; cs)
+ (push cs css)))))))
+ (print `(mapcar 'unify-charset ',unified-charsets))
+ (print `(dolist (f ',faces)
+ (face-spec-set f (get f 'face-defface-spec)
+ 'face-defface-spec)))
+ ;; This creates some rather large data structures that are
+ ;; more quickly reconstructed than read from the dumped
+ ;; Lisp state.
+ (print '(load "international/characters" nil t))
+ ;; This sets advice on a subr, so cannot be preloaded.
+ (print '(load "uniquify" nil t))
+ ;; Lisp functions have their DOC file offsets stored
+ ;; already, but for a subr it's hidden away from Lisp.
+ (print '(condition-case nil
+ (Snarf-documentation "DOC")
+ (file-missing
+ (message "Couldn't load DOC file"))))
+ (print `(dolist (cs ',coding-system-aliases)
+ (define-coding-system-alias (car cs) (cdr cs))))
+ (print `(progn
+ ;; (message "Done preloading!")
+ ;; (message "custom-delayed-init-variables = %S"
+ ;; custom-delayed-init-variables)
+ ;; (message "Running top-level = %S" top-level)
+ (setq debug-on-error t)
+ (use-global-map global-map)
+ (eval top-level)
+ ;; (message "top-level done!?")
+ )))
+ (goto-char (point-min))
+ (while (re-search-forward " (\\(defvar\\|setplist\\|fset\\) " nil t)
+ (goto-char (match-beginning 0))
+ (delete-char 1) (insert "\n"))
+ (message "Dumping into dumped.elc...saving...")
+ (let ((coding-system-for-write 'emacs-internal))
+ (write-region (point-min) (point-max) (buffer-name)))
+ (message "Dumping into dumped.elc...done")
+ ))
+
(kill-emacs)))
+(load "uniquify")
+
;; For machines with CANNOT_DUMP defined in config.h,
;; this file must be loaded each time Emacs is run.
;; So run the startup code now. First, remove `-l loadup' from args.
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index b3f452ca5b9..11d741c0b9e 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -810,15 +810,21 @@ non-nil result supercedes the xrefs produced by
(push (elisp--xref-find-definitions sym) lst))
(nreverse lst))))
+;; This used to use apply-partially, but that turned "obarray" into a
+;; reference to the actual obarray, not the symbol, and that's
+;; incompatible with the dumper code.
(defvar elisp--xref-identifier-completion-table
- (apply-partially #'completion-table-with-predicate
- obarray
- (lambda (sym)
- (or (boundp sym)
- (fboundp sym)
- (featurep sym)
- (facep sym)))
- 'strict))
+ (lambda (string pred2 action)
+ (completion-table-with-predicate obarray
+ (lambda (sym)
+ (or (boundp sym)
+ (fboundp sym)
+ (featurep sym)
+ (facep sym)))
+ 'strict
+ string
+ pred2
+ action)))
(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql elisp)))
elisp--xref-identifier-completion-table)
diff --git a/src/Makefile.in b/src/Makefile.in
index 57969d5fc58..ca250885033 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -529,10 +529,10 @@ ${lispintdir}/characters.elc: ${charscript:.el=.elc}
emacs$(EXEEXT): temacs$(EXEEXT) \
lisp.mk $(etc)/DOC $(lisp) \
$(lispsource)/international/charprop.el ${charsets}
+ LC_ALL=C $(RUN_TEMACS) --no-loadup -batch $(BUILD_DETAILS) -l loadup dump
ifeq ($(CANNOT_DUMP),yes)
ln -f temacs$(EXEEXT) $@
else
- LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup dump
ifneq ($(PAXCTL_dumped),)
$(PAXCTL_dumped) $@
endif
@@ -733,10 +733,10 @@ $(lispsource)/loaddefs.el: $(VCSWITNESS) | bootstrap-emacs$(EXEEXT)
## files from loadup.el in source form.
bootstrap-emacs$(EXEEXT): temacs$(EXEEXT)
$(MAKE) -C ../lisp update-subdirs
+ $(RUN_TEMACS) --no-loadup --batch $(BUILD_DETAILS) --load loadup bootstrap
ifeq ($(CANNOT_DUMP),yes)
ln -f temacs$(EXEEXT) $@
else
- $(RUN_TEMACS) --batch $(BUILD_DETAILS) --load loadup bootstrap
ifneq ($(PAXCTL_dumped),)
$(PAXCTL_dumped) emacs$(EXEEXT)
endif
diff --git a/src/alloc.c b/src/alloc.c
index 2cee6462564..73d33564843 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -221,7 +221,7 @@ alloc_unexec_post (void)
/* Default value of gc_cons_threshold (see below). */
-#define GC_DEFAULT_THRESHOLD (100000 * word_size)
+#define GC_DEFAULT_THRESHOLD (3000000 * word_size)
/* Global variables. */
struct emacs_globals globals;
diff --git a/src/charset.c b/src/charset.c
index 6ce2f902c81..15a50b29d0b 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -501,7 +501,6 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile,
large (larger than MAX_ALLOCA). */
head = record_xmalloc (sizeof *head);
entries = head;
- memset (entries, 0, sizeof (struct charset_map_entries));
n_entries = 0;
int ch = -1;
@@ -535,7 +534,6 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile,
{
entries->next = record_xmalloc (sizeof *entries->next);
entries = entries->next;
- memset (entries, 0, sizeof (struct charset_map_entries));
n_entries = 0;
}
int idx = n_entries;
diff --git a/src/coding.c b/src/coding.c
index 50ad206be69..0205358e312 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -10337,8 +10337,9 @@ usage: (define-coding-system-internal ...) */)
CHECK_NUMBER_CAR (reg_usage);
CHECK_NUMBER_CDR (reg_usage);
- request = Fcopy_sequence (args[coding_arg_iso2022_request]);
- for (tail = request; CONSP (tail); tail = XCDR (tail))
+ request = Qnil;
+ for (tail = args[coding_arg_iso2022_request];
+ CONSP (tail); tail = XCDR (tail))
{
int id;
Lisp_Object tmp1;
@@ -10350,7 +10351,8 @@ usage: (define-coding-system-internal ...) */)
CHECK_NATNUM_CDR (val);
if (XINT (XCDR (val)) >= 4)
error ("Invalid graphic register number: %"pI"d", XINT (XCDR (val)));
- XSETCAR (val, make_number (id));
+ request = Fcons (Fcons (make_number (id), XCDR (val)),
+ request);
}
flags = args[coding_arg_iso2022_flags];
diff --git a/src/doc.c b/src/doc.c
index 345e18b9186..ae09a3179a8 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -305,7 +305,7 @@ static bool
reread_doc_file (Lisp_Object file)
{
if (NILP (file))
- Fsnarf_documentation (Vdoc_file_name);
+ Fsnarf_documentation (Vdoc_file_name, Qnil);
else
Fload (file, Qt, Qt, Qt, Qnil);
@@ -466,7 +466,7 @@ aren't strings. */)
/* Scanning the DOC files and placing docstring offsets into functions. */
static void
-store_function_docstring (Lisp_Object obj, EMACS_INT offset)
+store_function_docstring (Lisp_Object obj, EMACS_INT offset, bool clear)
{
/* Don't use indirect_function here, or defaliases will apply their
docstrings to the base functions (Bug#2603). */
@@ -486,10 +486,16 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset)
|| (EQ (tem, Qclosure) && (fun = XCDR (fun), 1)))
{
tem = Fcdr (Fcdr (fun));
- if (CONSP (tem) && INTEGERP (XCAR (tem)))
- /* FIXME: This modifies typically pure hash-cons'd data, so its
- correctness is quite delicate. */
- XSETCAR (tem, make_number (offset));
+ if (CONSP (tem))
+ {
+ if (clear && STRINGP (XCAR (tem)))
+ /* Discard any string we may have loaded.
+ Also, 0 is a shorter placeholder in the dumped
+ environment file than the actual offset. */
+ XSETCAR (tem, make_number (0));
+ else if (INTEGERP (XCAR (tem)))
+ XSETCAR (tem, make_number (offset));
+ }
}
}
@@ -503,7 +509,7 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset)
/* This bytecode object must have a slot for the
docstring, since we've found a docstring for it. */
if (PVSIZE (fun) > COMPILED_DOC_STRING)
- ASET (fun, COMPILED_DOC_STRING, make_number (offset));
+ ASET (fun, COMPILED_DOC_STRING, make_number (clear ? 0 : offset));
else
{
AUTO_STRING (format, "No docstring slot for %s");
@@ -517,15 +523,22 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset)
DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
- 1, 1, 0,
+ 1, 2, 0,
doc: /* Used during Emacs initialization to scan the `etc/DOC...' file.
This searches the `etc/DOC...' file for doc strings and
records them in function and variable definitions.
-The function takes one argument, FILENAME, a string;
+The function takes one required argument, FILENAME, a string;
it specifies the file name (without a directory) of the DOC file.
That file is found in `../etc' now; later, when the dumped Emacs is run,
-the same file name is found in the `doc-directory'. */)
- (Lisp_Object filename)
+the same file name is found in the `doc-directory'.
+
+Optional second argument CLEAR, if set, causes the removal of
+variable-documentation properties and the replacement of function doc
+strings with dummy DOC file offsets when the documentation is found in
+the DOC file, to minimize storage use in preparation for dumping the
+Lisp environment state, with the expectation that Snarf-documentation
+will be called again after loading the dumped environment. */)
+ (Lisp_Object filename, Lisp_Object clear)
{
int fd;
char buf[1024 + 1];
@@ -644,16 +657,39 @@ the same file name is found in the `doc-directory'. */)
(doc starts with a `*'). */
if (!NILP (Fboundp (sym))
|| !NILP (Fmemq (sym, delayed_init)))
- Fput (sym, Qvariable_documentation,
- make_number ((pos + end + 1 - buf)
- * (end[1] == '*' ? -1 : 1)));
+ {
+ if (NILP (clear))
+ Fput (sym, Qvariable_documentation,
+ make_number ((pos + end + 1 - buf)
+ * (end[1] == '*' ? -1 : 1)));
+ else
+ /* Remove the variable-documentation property,
+ if present, even if it's nil (which makes
+ Fget unhelpful). */
+ {
+ Lisp_Object plist = Fsymbol_plist (sym);
+ Lisp_Object prev, prop;
+ if (EQ (Fcar (plist), Qvariable_documentation))
+ set_symbol_plist (sym, Fcdr (Fcdr (plist)));
+ else
+ for (prev = Fcdr (plist), prop = Fcdr (prev);
+ !NILP (prop);
+ prev = Fcdr (prop), prop = Fcdr (prev))
+ if (EQ (Fcar (prop), Qvariable_documentation))
+ {
+ Fsetcdr (prev, Fcdr (Fcdr (prop)));
+ break;
+ }
+ }
+ }
}
/* Attach a docstring to a function? */
else if (p[1] == 'F')
{
if (!NILP (Ffboundp (sym)))
- store_function_docstring (sym, pos + end + 1 - buf);
+ store_function_docstring (sym, pos + end + 1 - buf,
+ !NILP (clear));
}
else if (p[1] == 'S')
; /* Just a source file name boundary marker. Ignore it. */
diff --git a/src/emacs.c b/src/emacs.c
index 0fec7167588..4e812b19a0f 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1610,20 +1610,17 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
keys_of_keymap ();
keys_of_window ();
}
- else
- {
- /* Initialization that must be done even if the global variable
- initialized is non zero. */
+ /* Initialization that must be done even if the global variable
+ initialized is non zero. */
#ifdef HAVE_NTGUI
- globals_of_w32font ();
- globals_of_w32fns ();
- globals_of_w32menu ();
+ globals_of_w32font ();
+ globals_of_w32fns ();
+ globals_of_w32menu ();
#endif /* HAVE_NTGUI */
#if defined WINDOWSNT || defined HAVE_NTGUI
- globals_of_w32select ();
+ globals_of_w32select ();
#endif
- }
init_charset ();
@@ -1673,9 +1670,26 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
#endif
Vtop_level = list2 (Qload, build_unibyte_string (file));
}
- /* Unless next switch is -nl, load "loadup.el" first thing. */
if (! no_loadup)
- Vtop_level = list2 (Qload, build_string ("loadup.el"));
+ /* Unless next switch is -nl, load "dumped.elc" first thing.
+ If it fails, we won't be able to run. */
+ {
+ /* We could let the user see that we're (still) loading the
+ Lisp environment, but the "done" message will hide the
+ "For information about..." message that we want displayed
+ when we're finished. */
+ Lisp_Object load = list4 (Qload,
+ build_string ("../src/dumped.elc"),
+ Qnil, Qt);
+ /* XXX We need a way for Lisp to cause Emacs to exit, with
+ an error message to stderr after restoring tty modes. */
+ /* (condition-case nil bodyform (file-missing (kill-emacs 42))) */
+ Vtop_level = list4 (Qcondition_case,
+ Qnil,
+ load,
+ list2 (Qfile_missing,
+ list2 (Qkill_emacs, make_number (42))));
+ }
}
/* Set up for profiling. This is known to work on FreeBSD,
@@ -2506,6 +2520,7 @@ syms_of_emacs (void)
DEFSYM (Qrisky_local_variable, "risky-local-variable");
DEFSYM (Qkill_emacs, "kill-emacs");
DEFSYM (Qkill_emacs_hook, "kill-emacs-hook");
+ DEFSYM (Qcondition_case, "condition-case");
#ifndef CANNOT_DUMP
defsubr (&Sdump_emacs);
diff --git a/src/print.c b/src/print.c
index 12edf015892..aca808f2750 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1131,16 +1131,19 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
print_object (obj, printcharfun, escapeflag);
}
-#define PRINT_CIRCLE_CANDIDATE_P(obj) \
- (STRINGP (obj) || CONSP (obj) \
- || (VECTORLIKEP (obj) \
- && (VECTORP (obj) || COMPILEDP (obj) \
- || CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj) \
- || HASH_TABLE_P (obj) || FONTP (obj) \
- || RECORDP (obj))) \
- || (! NILP (Vprint_gensym) \
- && SYMBOLP (obj) \
- && !SYMBOL_INTERNED_P (obj)))
+#define PRINT_CIRCLE_CANDIDATE_P(obj) \
+ (STRINGP (obj) || CONSP (obj) \
+ || (VECTORLIKEP (obj) \
+ && (VECTORP (obj) || COMPILEDP (obj) \
+ || CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj) \
+ || HASH_TABLE_P (obj) || FONTP (obj) \
+ || RECORDP (obj))) \
+ || (SYMBOLP (obj) \
+ && !SYMBOL_INTERNED_P (obj) \
+ && ! NILP (Vprint_gensym)) \
+ || (SYMBOLP (obj) \
+ && SYMBOL_INTERNED_P (obj) \
+ && ! NILP (Vprint_symbols_as_references)))
/* Construct Vprint_number_table according to the structure of OBJ.
OBJ itself and all its elements will be added to Vprint_number_table
@@ -1181,8 +1184,9 @@ print_preprocess (Lisp_Object obj)
if (!HASH_TABLE_P (Vprint_number_table))
Vprint_number_table = CALLN (Fmake_hash_table, QCtest, Qeq);
- /* In case print-circle is nil and print-gensym is t,
- add OBJ to Vprint_number_table only when OBJ is a symbol. */
+ /* In case print-circle is nil and print-gensym or
+ print-symbols-as-references is t, add OBJ to Vprint_number_table only
+ when OBJ is a symbol. */
if (! NILP (Vprint_circle) || SYMBOLP (obj))
{
Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil);
@@ -2013,7 +2017,20 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
|| EQ (XCAR (obj), Qcomma_at)
|| EQ (XCAR (obj), Qcomma_dot)))
{
- print_object (XCAR (obj), printcharfun, false);
+ /* If print-symbols-as-references is enabled, symbols may
+ print with "#N=" or "#N#" form. When we print a cons
+ cell with parens and separated elements, that's fine, but
+ for comma symbols we depend on the reader to generate the
+ cons cell from the special syntax. The Lisp reader will
+ treat "#1=,#2=foo" as setting reference 1 to ",foo", not
+ to ",", so we can't use print_object to print out the
+ comma symbols without breaking the ability to read the
+ result back properly. */
+ printchar (',', printcharfun);
+ if (EQ (XCAR (obj), Qcomma_at))
+ printchar ('@', printcharfun);
+ else if (EQ (XCAR (obj), Qcomma_dot))
+ printchar ('.', printcharfun);
new_backquote_output--;
print_object (XCAR (XCDR (obj)), printcharfun, escapeflag);
new_backquote_output++;
@@ -2422,6 +2439,15 @@ the value is different from what is guessed in the current charset
priorities. */);
Vprint_charset_text_property = Qdefault;
+ DEFVAR_LISP ("print-symbols-as-references", Vprint_symbols_as_references,
+ doc: /* Non-nil means print interned symbols using #N= and #N# syntax.
+If nil, symbols are printed normally.
+
+Setting this true makes the output harder for a human to read, but may
+parse more efficiently as input to the Lisp reader if some symbols appear
+in the output many times. */);
+ Vprint_symbols_as_references = Qnil;
+
/* prin1_to_string_buffer initialized in init_buffer_once in buffer.c */
staticpro (&Vprin1_to_string_buffer);
diff --git a/src/syntax.c b/src/syntax.c
index dcaca22f0e2..209acc2aed0 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -1029,6 +1029,18 @@ It is a copy of the TABLE, which defaults to the standard syntax table. */)
return copy;
}
+DEFUN ("internal--set-standard-syntax-table",
+ Finternal_set_standard_syntax_table,
+ Sinternal_set_standard_syntax_table, 1, 1, 0,
+ doc: /* Replace the standard syntax table, used for new buffers. */)
+ (Lisp_Object table)
+{
+ check_syntax_table (table);
+ Vstandard_syntax_table = table;
+ Fset_char_table_parent (table, Qnil);
+ return table;
+}
+
DEFUN ("set-syntax-table", Fset_syntax_table, Sset_syntax_table, 1, 1, 0,
doc: /* Select a new syntax table for the current buffer.
One argument, a syntax table. */)
@@ -3769,6 +3781,7 @@ In both cases, LIMIT bounds the search. */);
defsubr (&Sstring_to_syntax);
defsubr (&Smodify_syntax_entry);
defsubr (&Sinternal_describe_syntax_value);
+ defsubr (&Sinternal_set_standard_syntax_table);
defsubr (&Sforward_word);
diff --git a/src/unexw32.c b/src/unexw32.c
index 904447c3ec9..65f24ca27c1 100644
--- a/src/unexw32.c
+++ b/src/unexw32.c
@@ -48,7 +48,7 @@ extern char *my_begbss_static;
#include "w32heap.h"
/* Basically, our "initialized" flag. */
-BOOL using_dynamic_heap = FALSE;
+BOOL using_dynamic_heap = TRUE;
void get_section_info (file_data *p_file);
void copy_executable_and_dump_data (file_data *, file_data *);
diff --git a/src/xfaces.c b/src/xfaces.c
index 86bb9b0b496..b9ced74cd84 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -3212,6 +3212,13 @@ FRAME 0 means change the face on all frames, and change the default
cons = XCAR (Vparam_value_alist);
XSETCAR (cons, param);
XSETCDR (cons, value);
+
+ /* Fmodify_frame_parameters may update faces and use the
+ cache. */
+ struct frame *f = XFRAME (frame);
+ if (FRAME_FACE_CACHE (f) == NULL)
+ FRAME_FACE_CACHE (f) = make_face_cache (f);
+
Fmodify_frame_parameters (frame, Vparam_value_alist);
}
}