-;;; bytecomp.el --- compilation of Lisp code into byte code
+;;; bytecomp.el --- compilation of Lisp code into byte code -*- lexical-binding: t -*-
-;; Copyright (C) 1985, 1986, 1987, 1992, 1994, 1998, 2000, 2001, 2002,
-;; 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;; Copyright (C) 1985-1987, 1992, 1994, 1998, 2000-2011
;; Free Software Foundation, Inc.
;; Author: Jamie Zawinski <jwz@lucid.com>
;;; Code:
+;; FIXME: Use lexical-binding and get rid of the atrocious "bytecomp-"
+;; variable prefix.
+
;; ========================================================================
;; Entry points:
;; byte-recompile-directory, byte-compile-file,
+;; byte-recompile-file,
;; batch-byte-compile, batch-byte-recompile-directory,
;; byte-compile, compile-defun,
;; display-call-tree
(require 'backquote)
(require 'macroexp)
+(require 'cconv)
(eval-when-compile (require 'cl))
(or (fboundp 'defsubst)
;; This really ought to be loaded already!
(load "byte-run"))
-;; We want to do (require 'byte-lexbind) when compiling, to avoid compilation
-;; errors; however that file also wants to do (require 'bytecomp) for the
-;; same reason. Since we know it's OK to load byte-lexbind.el second, we
-;; have that file require a feature that's provided before at the beginning
-;; of this file, to avoid an infinite require loop.
-;; `eval-when-compile' is defined in byte-run.el, so it must come after the
-;; preceding load expression.
-(provide 'bytecomp-preload)
-(eval-when-compile (require 'byte-lexbind))
-
;; The feature of compiling in a specific target Emacs version
;; has been turned off because compile time options are a bad idea.
(defmacro byte-compile-single-version () nil)
(defmacro byte-compile-version-cond (cond) cond)
-;; The crud you see scattered through this file of the form
-;; (or (and (boundp 'epoch::version) epoch::version)
-;; (string-lessp emacs-version "19"))
-;; is because the Epoch folks couldn't be bothered to follow the
-;; normal emacs version numbering convention.
-
-;; (if (byte-compile-version-cond
-;; (or (and (boundp 'epoch::version) epoch::version)
-;; (string-lessp emacs-version "19")))
-;; (progn
-;; ;; emacs-18 compatibility.
-;; (defvar baud-rate (baud-rate)) ;Define baud-rate if it's undefined
-;;
-;; (if (byte-compile-single-version)
-;; (defmacro byte-code-function-p (x) "Emacs 18 doesn't have these." nil)
-;; (defun byte-code-function-p (x) "Emacs 18 doesn't have these." nil))
-;;
-;; (or (and (fboundp 'member)
-;; ;; avoid using someone else's possibly bogus definition of this.
-;; (subrp (symbol-function 'member)))
-;; (defun member (elt list)
-;; "like memq, but uses equal instead of eq. In v19, this is a subr."
-;; (while (and list (not (equal elt (car list))))
-;; (setq list (cdr list)))
-;; list))))
-
(defgroup bytecomp nil
"Emacs Lisp byte-compiler."
(defvar byte-compile-disable-print-circle nil
"If non-nil, disable `print-circle' on printing a byte-compiled code.")
+(make-obsolete-variable 'byte-compile-disable-print-circle nil "24.1")
;;;###autoload(put 'byte-compile-disable-print-circle 'safe-local-variable 'booleanp)
(defcustom byte-compile-dynamic-docstrings t
:type 'boolean)
;;;###autoload(put 'byte-compile-dynamic-docstrings 'safe-local-variable 'booleanp)
+(defconst byte-compile-log-buffer "*Compile-Log*"
+ "Name of the byte-compiler's log buffer.")
+
(defcustom byte-optimize-log nil
- "If true, the byte-compiler will log its optimizations into *Compile-Log*.
+ "If non-nil, the byte-compiler will log its optimizations.
If this is 'source, then only source-level optimizations will be logged.
-If it is 'byte, then only byte-level optimizations will be logged."
+If it is 'byte, then only byte-level optimizations will be logged.
+The information is logged to `byte-compile-log-buffer'."
:group 'bytecomp
:type '(choice (const :tag "none" nil)
(const :tag "all" t)
(set :menu-tag "Some"
,@(mapcar (lambda (x) `(const ,x))
byte-compile-warning-types))))
-;;;###autoload(put 'byte-compile-warnings 'safe-local-variable 'byte-compile-warnings-safe-p)
;;;###autoload
-(defun byte-compile-warnings-safe-p (x)
- "Return non-nil if X is valid as a value of `byte-compile-warnings'."
- (or (booleanp x)
- (and (listp x)
- (if (eq (car x) 'not) (setq x (cdr x))
- t)
- (equal (mapcar
- (lambda (e)
- (when (memq e byte-compile-warning-types)
- e))
- x)
- x))))
+(put 'byte-compile-warnings 'safe-local-variable
+ (lambda (v)
+ (or (symbolp v)
+ (null (delq nil (mapcar (lambda (x) (not (symbolp x))) v))))))
(defun byte-compile-warning-enabled-p (warning)
"Return non-nil if WARNING is enabled, according to `byte-compile-warnings'."
:type '(choice (const name) (const callers) (const calls)
(const calls+callers) (const nil)))
-;(defvar byte-compile-debug nil)
(defvar byte-compile-debug t)
-
-;; (defvar byte-compile-overwrite-file t
-;; "If nil, old .elc files are deleted before the new is saved, and .elc
-;; files will have the same modes as the corresponding .el file. Otherwise,
-;; existing .elc files will simply be overwritten, and the existing modes
-;; will not be changed. If this variable is nil, then an .elc file which
-;; is a symbolic link will be turned into a normal file, instead of the file
-;; which the link points to being overwritten.")
+(setq debug-on-error t)
(defvar byte-compile-constants nil
"List of all constants encountered during compilation of this form.")
(defvar byte-compile-variables nil
"List of all variables encountered during compilation of this form.")
(defvar byte-compile-bound-variables nil
- "List of variables bound in the context of the current form.
+ "List of dynamic variables bound in the context of the current form.
This list lives partly on the stack.")
(defvar byte-compile-const-variables nil
"List of variables declared as constants during compilation of this file.")
'(
;; (byte-compiler-options . (lambda (&rest forms)
;; (apply 'byte-compiler-options-handler forms)))
+ (declare-function . byte-compile-macroexpand-declare-function)
(eval-when-compile . (lambda (&rest body)
(list
'quote
+ ;; FIXME: is that right in lexbind code?
(byte-compile-eval
- (byte-compile-top-level
- (macroexpand-all
- (cons 'progn body)
- byte-compile-initial-macro-environment))))))
+ (byte-compile-top-level
+ (macroexpand-all
+ (cons 'progn body)
+ byte-compile-initial-macro-environment))))))
(eval-and-compile . (lambda (&rest body)
(byte-compile-eval-before-compile (cons 'progn body))
(cons 'progn body))))
;; Variables for lexical binding
(defvar byte-compile-lexical-environment nil
"The current lexical environment.")
-(defvar byte-compile-current-heap-environment nil
- "If non-nil, a descriptor for the current heap-allocated lexical environment.")
-(defvar byte-compile-current-num-closures 0
- "The number of lexical closures that close over `byte-compile-current-heap-environment'.")
(defvar byte-compile-tag-number 0)
(defvar byte-compile-output nil
(byte-defop 114 0 byte-save-current-buffer
"To make a binding to record the current buffer")
(byte-defop 115 0 byte-set-mark-OBSOLETE)
-(byte-defop 116 1 byte-interactive-p)
;; These ops are new to v19
(byte-defop 117 0 byte-forward-char)
(byte-defop 138 0 byte-save-excursion
"to make a binding to record the buffer, point and mark")
-(byte-defop 139 0 byte-save-window-excursion
- "to make a binding to record entire window configuration")
(byte-defop 140 0 byte-save-restriction
"to make a binding to record the current buffer clipping restrictions")
(byte-defop 141 -1 byte-catch
;; Takes, on stack, the buffer name.
;; Binds standard-output and does some other things.
;; Returns with temp buffer on the stack in place of buffer name.
-(byte-defop 144 0 byte-temp-output-buffer-setup)
+;; (byte-defop 144 0 byte-temp-output-buffer-setup)
;; For exit from with-output-to-temp-buffer.
;; Expects the temp buffer on the stack underneath value to return.
;; Pops them both, then pushes the value back on.
;; Unbinds standard-output and makes the temp buffer visible.
-(byte-defop 145 -1 byte-temp-output-buffer-show)
+;; (byte-defop 145 -1 byte-temp-output-buffer-show)
;; these ops are new to v19
(byte-defop 178 -1 byte-stack-set) ; stack offset in following one byte
(byte-defop 179 -1 byte-stack-set2) ; stack offset in following two bytes
-(byte-defop 180 1 byte-vec-ref) ; vector offset in following one byte
-(byte-defop 181 -1 byte-vec-set) ; vector offset in following one byte
;; if (following one byte & 0x80) == 0
;; discard (following one byte & 0x7F) stack entries
(bytes-var (car (last args 2)))
(pc-var (car (last args))))
`(setq ,bytes-var ,(if (null (cdr byte-exprs))
- `(cons ,@byte-exprs ,bytes-var)
- `(nconc (list ,@(reverse byte-exprs)) ,bytes-var))
- ,pc-var (+ ,(length byte-exprs) ,pc-var))))
+ `(progn (assert (<= 0 ,(car byte-exprs)))
+ (cons ,@byte-exprs ,bytes-var))
+ `(nconc (list ,@(reverse byte-exprs)) ,bytes-var))
+ ,pc-var (+ ,(length byte-exprs) ,pc-var))))
(defmacro byte-compile-push-bytecode-const2 (opcode const2 bytes pc)
"Push OPCODE and the two-byte constant CONST2 onto BYTES, and add 3 to PC.
(dolist (lap-entry lap)
(setq op (car lap-entry)
off (cdr lap-entry))
- (cond ((not (symbolp op))
- (error "Non-symbolic opcode `%s'" op))
- ((eq op 'TAG)
- (setcar off pc))
- ((null op)
- ;; a no-op added by `byte-compile-delay-out'
- (unless (zerop off)
- (error
- "Placeholder added by `byte-compile-delay-out' not filled in.")
- ))
- (t
- (if (eq op 'byte-discardN-preserve-tos)
- ;; byte-discardN-preserve-tos is a psuedo op, which is actually
- ;; the same as byte-discardN with a modified argument
- (setq opcode byte-discardN)
- (setq opcode (symbol-value op)))
- (cond ((memq op byte-goto-ops)
- ;; goto
- (byte-compile-push-bytecodes opcode nil (cdr off) bytes pc)
- (push bytes patchlist))
- ((and (consp off)
- ;; Variable or constant reference
- (progn (setq off (cdr off))
- (eq op 'byte-constant)))
- ;; constant ref
- (if (< off byte-constant-limit)
- (byte-compile-push-bytecodes (+ byte-constant off)
- bytes pc)
- (byte-compile-push-bytecode-const2 byte-constant2 off
- bytes pc)))
- ((and (= opcode byte-stack-set)
- (> off 255))
- ;; Use the two-byte version of byte-stack-set if the
- ;; offset is too large for the normal version.
- (byte-compile-push-bytecode-const2 byte-stack-set2 off
- bytes pc))
- ((and (>= opcode byte-listN)
- (< opcode byte-discardN))
- ;; These insns all put their operand into one extra byte.
- (byte-compile-push-bytecodes opcode off bytes pc))
- ((= opcode byte-discardN)
- ;; byte-discardN is wierd in that it encodes a flag in the
- ;; top bit of its one-byte argument. If the argument is
- ;; too large to fit in 7 bits, the opcode can be repeated.
- (let ((flag (if (eq op 'byte-discardN-preserve-tos) #x80 0)))
- (while (> off #x7f)
- (byte-compile-push-bytecodes opcode (logior #x7f flag) bytes pc)
- (setq off (- off #x7f)))
- (byte-compile-push-bytecodes opcode (logior off flag) bytes pc)))
- ((null off)
- ;; opcode that doesn't use OFF
- (byte-compile-push-bytecodes opcode bytes pc))
- ;; The following three cases are for the special
- ;; insns that encode their operand into 0, 1, or 2
- ;; extra bytes depending on its magnitude.
- ((< off 6)
- (byte-compile-push-bytecodes (+ opcode off) bytes pc))
- ((< off 256)
- (byte-compile-push-bytecodes (+ opcode 6) off bytes pc))
- (t
- (byte-compile-push-bytecode-const2 (+ opcode 7) off
- bytes pc))))))
+ (cond
+ ((not (symbolp op))
+ (error "Non-symbolic opcode `%s'" op))
+ ((eq op 'TAG)
+ (setcar off pc))
+ ((null op)
+ ;; a no-op added by `byte-compile-delay-out'
+ (unless (zerop off)
+ (error
+ "Placeholder added by `byte-compile-delay-out' not filled in.")
+ ))
+ (t
+ (setq opcode
+ (if (eq op 'byte-discardN-preserve-tos)
+ ;; byte-discardN-preserve-tos is a pseudo op, which
+ ;; is actually the same as byte-discardN
+ ;; with a modified argument.
+ byte-discardN
+ (symbol-value op)))
+ (cond ((memq op byte-goto-ops)
+ ;; goto
+ (byte-compile-push-bytecodes opcode nil (cdr off) bytes pc)
+ (push bytes patchlist))
+ ((or (and (consp off)
+ ;; Variable or constant reference
+ (progn
+ (setq off (cdr off))
+ (eq op 'byte-constant)))
+ (and (eq op 'byte-constant) ;; 'byte-closed-var
+ (integerp off)))
+ ;; constant ref
+ (if (< off byte-constant-limit)
+ (byte-compile-push-bytecodes (+ byte-constant off)
+ bytes pc)
+ (byte-compile-push-bytecode-const2 byte-constant2 off
+ bytes pc)))
+ ((and (= opcode byte-stack-set)
+ (> off 255))
+ ;; Use the two-byte version of byte-stack-set if the
+ ;; offset is too large for the normal version.
+ (byte-compile-push-bytecode-const2 byte-stack-set2 off
+ bytes pc))
+ ((and (>= opcode byte-listN)
+ (< opcode byte-discardN))
+ ;; These insns all put their operand into one extra byte.
+ (byte-compile-push-bytecodes opcode off bytes pc))
+ ((= opcode byte-discardN)
+ ;; byte-discardN is weird in that it encodes a flag in the
+ ;; top bit of its one-byte argument. If the argument is
+ ;; too large to fit in 7 bits, the opcode can be repeated.
+ (let ((flag (if (eq op 'byte-discardN-preserve-tos) #x80 0)))
+ (while (> off #x7f)
+ (byte-compile-push-bytecodes opcode (logior #x7f flag) bytes pc)
+ (setq off (- off #x7f)))
+ (byte-compile-push-bytecodes opcode (logior off flag) bytes pc)))
+ ((null off)
+ ;; opcode that doesn't use OFF
+ (byte-compile-push-bytecodes opcode bytes pc))
+ ((and (eq opcode byte-stack-ref) (eq off 0))
+ ;; (stack-ref 0) is really just another name for `dup'.
+ (debug) ;FIXME: When would this happen?
+ (byte-compile-push-bytecodes byte-dup bytes pc))
+ ;; The following three cases are for the special
+ ;; insns that encode their operand into 0, 1, or 2
+ ;; extra bytes depending on its magnitude.
+ ((< off 6)
+ (byte-compile-push-bytecodes (+ opcode off) bytes pc))
+ ((< off 256)
+ (byte-compile-push-bytecodes (+ opcode 6) off bytes pc))
+ (t
+ (byte-compile-push-bytecode-const2 (+ opcode 7) off
+ bytes pc))))))
;;(if (not (= pc (length bytes)))
;; (error "Compiler error: pc mismatch - %s %s" pc (length bytes)))
;; Log something that isn't a warning.
(defun byte-compile-log-1 (string)
- (with-current-buffer "*Compile-Log*"
+ (with-current-buffer byte-compile-log-buffer
(let ((inhibit-read-only t))
(goto-char (point-max))
(byte-compile-warning-prefix nil nil)
;; This no-op function is used as the value of warning-series
;; to tell inner calls to displaying-byte-compile-warnings
;; not to bind warning-series.
-(defun byte-compile-warning-series (&rest ignore)
+(defun byte-compile-warning-series (&rest _ignore)
nil)
;; (compile-mode) will cause this to be loaded.
(declare-function compilation-forget-errors "compile" ())
-;; Log the start of a file in *Compile-Log*, and mark it as done.
+;; Log the start of a file in `byte-compile-log-buffer', and mark it as done.
;; Return the position of the start of the page in the log buffer.
;; But do nothing in batch mode.
(defun byte-compile-log-file ()
(and (not (equal byte-compile-current-file byte-compile-last-logged-file))
(not noninteractive)
- (with-current-buffer (get-buffer-create "*Compile-Log*")
+ (with-current-buffer (get-buffer-create byte-compile-log-buffer)
(goto-char (point-max))
(let* ((inhibit-read-only t)
(dir (and byte-compile-current-file
(compilation-forget-errors)
pt))))
-;; Log a message STRING in *Compile-Log*.
+;; Log a message STRING in `byte-compile-log-buffer'.
;; Also log the current function and file if not already done.
(defun byte-compile-log-warning (string &optional fill level)
(let ((warning-prefix-function 'byte-compile-warning-prefix)
(warning-type-format "")
(warning-fill-prefix (if fill " "))
(inhibit-read-only t))
- (display-warning 'bytecomp string level "*Compile-Log*")))
+ (display-warning 'bytecomp string level byte-compile-log-buffer)))
(defun byte-compile-warn (format &rest args)
"Issue a byte compiler warning; use (format FORMAT ARGS...) for message."
(byte-compile-log-warning
(error-message-string error-info)
nil :error))
-
-;;; Used by make-obsolete.
-(defun byte-compile-obsolete (form)
- (byte-compile-set-symbol-position (car form))
- (byte-compile-warn-obsolete (car form))
- (funcall (or (cadr (get (car form) 'byte-obsolete-info)) ; handler
- 'byte-compile-normal-call) form))
\f
;;; sanity-checking arglists
(t fn)))))))
(defun byte-compile-arglist-signature (arglist)
- (let ((args 0)
- opts
- restp)
- (while arglist
- (cond ((eq (car arglist) '&optional)
- (or opts (setq opts 0)))
- ((eq (car arglist) '&rest)
- (if (cdr arglist)
- (setq restp t
- arglist nil)))
- (t
- (if opts
- (setq opts (1+ opts))
+ (if (integerp arglist)
+ ;; New style byte-code arglist.
+ (cons (logand arglist 127) ;Mandatory.
+ (if (zerop (logand arglist 128)) ;No &rest.
+ (lsh arglist -8))) ;Nonrest.
+ ;; Old style byte-code, or interpreted function.
+ (let ((args 0)
+ opts
+ restp)
+ (while arglist
+ (cond ((eq (car arglist) '&optional)
+ (or opts (setq opts 0)))
+ ((eq (car arglist) '&rest)
+ (if (cdr arglist)
+ (setq restp t
+ arglist nil)))
+ (t
+ (if opts
+ (setq opts (1+ opts))
(setq args (1+ args)))))
- (setq arglist (cdr arglist)))
- (cons args (if restp nil (if opts (+ args opts) args)))))
+ (setq arglist (cdr arglist)))
+ (cons args (if restp nil (if opts (+ args opts) args))))))
(defun byte-compile-arglist-signatures-congruent-p (old new)
;; Warn if the function or macro is being redefined with a different
;; number of arguments.
(defun byte-compile-arglist-warn (form macrop)
- (let ((old (byte-compile-fdefinition (nth 1 form) macrop)))
+ (let* ((name (nth 1 form))
+ (old (byte-compile-fdefinition name macrop)))
(if (and old (not (eq old t)))
(progn
(and (eq 'macro (car-safe old))
(eq 'lambda (car-safe (cdr-safe old)))
(setq old (cdr old)))
(let ((sig1 (byte-compile-arglist-signature
- (if (eq 'lambda (car-safe old))
- (nth 1 old)
- (if (byte-code-function-p old)
- (aref old 0)
- '(&rest def)))))
+ (pcase old
+ (`(lambda ,args . ,_) args)
+ (`(closure ,_ ,_ ,args . ,_) args)
+ ((pred byte-code-function-p) (aref old 0))
+ (t '(&rest def)))))
(sig2 (byte-compile-arglist-signature (nth 2 form))))
(unless (byte-compile-arglist-signatures-congruent-p sig1 sig2)
- (byte-compile-set-symbol-position (nth 1 form))
+ (byte-compile-set-symbol-position name)
(byte-compile-warn
"%s %s used to take %s %s, now takes %s"
(if (eq (car form) 'defun) "function" "macro")
- (nth 1 form)
+ name
(byte-compile-arglist-signature-string sig1)
(if (equal sig1 '(1 . 1)) "argument" "arguments")
(byte-compile-arglist-signature-string sig2)))))
;; This is the first definition. See if previous calls are compatible.
- (let ((calls (assq (nth 1 form) byte-compile-unresolved-functions))
+ (let ((calls (assq name byte-compile-unresolved-functions))
nums sig min max)
- (if calls
- (progn
- (setq sig (byte-compile-arglist-signature (nth 2 form))
- nums (sort (copy-sequence (cdr calls)) (function <))
- min (car nums)
- max (car (nreverse nums)))
- (when (or (< min (car sig))
- (and (cdr sig) (> max (cdr sig))))
- (byte-compile-set-symbol-position (nth 1 form))
- (byte-compile-warn
- "%s being defined to take %s%s, but was previously called with %s"
- (nth 1 form)
- (byte-compile-arglist-signature-string sig)
- (if (equal sig '(1 . 1)) " arg" " args")
- (byte-compile-arglist-signature-string (cons min max))))
-
- (setq byte-compile-unresolved-functions
- (delq calls byte-compile-unresolved-functions)))))
- )))
+ (when calls
+ (when (and (symbolp name)
+ (eq (get name 'byte-optimizer)
+ 'byte-compile-inline-expand))
+ (byte-compile-warn "defsubst `%s' was used before it was defined"
+ name))
+ (setq sig (byte-compile-arglist-signature (nth 2 form))
+ nums (sort (copy-sequence (cdr calls)) (function <))
+ min (car nums)
+ max (car (nreverse nums)))
+ (when (or (< min (car sig))
+ (and (cdr sig) (> max (cdr sig))))
+ (byte-compile-set-symbol-position name)
+ (byte-compile-warn
+ "%s being defined to take %s%s, but was previously called with %s"
+ name
+ (byte-compile-arglist-signature-string sig)
+ (if (equal sig '(1 . 1)) " arg" " args")
+ (byte-compile-arglist-signature-string (cons min max))))
+
+ (setq byte-compile-unresolved-functions
+ (delq calls byte-compile-unresolved-functions)))))))
(defvar byte-compile-cl-functions nil
"List of functions defined in CL.")
;; but such warnings are never useful,
;; so don't warn about them.
macroexpand cl-macroexpand-all
- cl-compiling-file)))
- ;; Avoid warnings for things which are safe because they
- ;; have suitable compiler macros, but those aren't
- ;; expanded at this stage. There should probably be more
- ;; here than caaar and friends.
- (not (and (eq (get func 'byte-compile)
- 'cl-byte-compile-compiler-macro)
- (string-match "\\`c[ad]+r\\'" (symbol-name func)))))
+ cl-compiling-file))))
(byte-compile-warn "function `%s' from cl package called at runtime"
func)))
form)
(if any-value
(or (memq symbol byte-compile-const-variables)
;; FIXME: We should provide a less intrusive way to find out
- ;; is a variable is "constant".
+ ;; if a variable is "constant".
(and (boundp symbol)
(condition-case nil
(progn (set symbol (symbol-value symbol)) nil)
((byte-compile-const-symbol-p ,form))))
(defmacro byte-compile-close-variables (&rest body)
+ (declare (debug t))
(cons 'let
(cons '(;;
;; Close over these variables to encapsulate the
body)))
(defmacro displaying-byte-compile-warnings (&rest body)
+ (declare (debug t))
`(let* ((--displaying-byte-compile-warnings-fn (lambda () ,@body))
(warning-series-started
(and (markerp warning-series)
(eq (marker-buffer warning-series)
- (get-buffer "*Compile-Log*")))))
+ (get-buffer byte-compile-log-buffer)))))
(byte-compile-find-cl-functions)
(if (or (eq warning-series 'byte-compile-warning-series)
warning-series-started)
nil
(save-some-buffers)
(force-mode-line-update))
- (with-current-buffer (get-buffer-create "*Compile-Log*")
+ (with-current-buffer (get-buffer-create byte-compile-log-buffer)
(setq default-directory (expand-file-name bytecomp-directory))
;; compilation-mode copies value of default-directory.
(unless (eq major-mode 'compilation-mode)
(setq bytecomp-directory (car bytecomp-directories))
(message "Checking %s..." bytecomp-directory)
(let ((bytecomp-files (directory-files bytecomp-directory))
- bytecomp-source bytecomp-dest)
+ bytecomp-source)
(dolist (bytecomp-file bytecomp-files)
(setq bytecomp-source
(expand-file-name bytecomp-file bytecomp-directory))
(not (auto-save-file-name-p bytecomp-source))
(not (string-equal dir-locals-file
(file-name-nondirectory
- bytecomp-source)))
- (setq bytecomp-dest
- (byte-compile-dest-file bytecomp-source))
- (if (file-exists-p bytecomp-dest)
- ;; File was already compiled.
- (or bytecomp-force
- (file-newer-than-file-p bytecomp-source
- bytecomp-dest))
- ;; No compiled file exists yet.
- (and bytecomp-arg
- (or (eq 0 bytecomp-arg)
- (y-or-n-p (concat "Compile "
- bytecomp-source "? "))))))
- (progn (if (and noninteractive (not byte-compile-verbose))
- (message "Compiling %s..." bytecomp-source))
- (let ((bytecomp-res (byte-compile-file
- bytecomp-source)))
+ bytecomp-source))))
+ (progn (let ((bytecomp-res (byte-recompile-file
+ bytecomp-source
+ bytecomp-force bytecomp-arg)))
(cond ((eq bytecomp-res 'no-byte-compile)
(setq skip-count (1+ skip-count)))
((eq bytecomp-res t)
"Non-nil to prevent byte-compiling of Emacs Lisp code.
This is normally set in local file variables at the end of the elisp file:
-;; Local Variables:\n;; no-byte-compile: t\n;; End: ")
+\;; Local Variables:\n;; no-byte-compile: t\n;; End: ") ;Backslash for compile-main.
;;;###autoload(put 'no-byte-compile 'safe-local-variable 'booleanp)
+(defun byte-recompile-file (bytecomp-filename &optional bytecomp-force bytecomp-arg load)
+ "Recompile BYTECOMP-FILENAME file if it needs recompilation.
+This happens when its `.elc' file is older than itself.
+
+If the `.elc' file exists and is up-to-date, normally this
+function *does not* compile BYTECOMP-FILENAME. However, if the
+prefix argument BYTECOMP-FORCE is set, that means do compile
+BYTECOMP-FILENAME even if the destination already exists and is
+up-to-date.
+
+If the `.elc' file does not exist, normally this function *does
+not* compile BYTECOMP-FILENAME. If BYTECOMP-ARG is 0, that means
+compile the file even if it has never been compiled before.
+A nonzero BYTECOMP-ARG means ask the user.
+
+If LOAD is set, `load' the file after compiling.
+
+The value returned is the value returned by `byte-compile-file',
+or 'no-byte-compile if the file did not need recompilation."
+ (interactive
+ (let ((bytecomp-file buffer-file-name)
+ (bytecomp-file-name nil)
+ (bytecomp-file-dir nil))
+ (and bytecomp-file
+ (eq (cdr (assq 'major-mode (buffer-local-variables)))
+ 'emacs-lisp-mode)
+ (setq bytecomp-file-name (file-name-nondirectory bytecomp-file)
+ bytecomp-file-dir (file-name-directory bytecomp-file)))
+ (list (read-file-name (if current-prefix-arg
+ "Byte compile file: "
+ "Byte recompile file: ")
+ bytecomp-file-dir bytecomp-file-name nil)
+ current-prefix-arg)))
+ (let ((bytecomp-dest
+ (byte-compile-dest-file bytecomp-filename))
+ ;; Expand now so we get the current buffer's defaults
+ (bytecomp-filename (expand-file-name bytecomp-filename)))
+ (if (if (file-exists-p bytecomp-dest)
+ ;; File was already compiled
+ ;; Compile if forced to, or filename newer
+ (or bytecomp-force
+ (file-newer-than-file-p bytecomp-filename
+ bytecomp-dest))
+ (and bytecomp-arg
+ (or (eq 0 bytecomp-arg)
+ (y-or-n-p (concat "Compile "
+ bytecomp-filename "? ")))))
+ (progn
+ (if (and noninteractive (not byte-compile-verbose))
+ (message "Compiling %s..." bytecomp-filename))
+ (byte-compile-file bytecomp-filename load))
+ (when load (load bytecomp-filename))
+ 'no-byte-compile)))
+
;;;###autoload
(defun byte-compile-file (bytecomp-filename &optional load)
"Compile a file of Lisp code named BYTECOMP-FILENAME into a file of byte code.
(bytecomp-file-name nil)
(bytecomp-file-dir nil))
(and bytecomp-file
- (eq (cdr (assq 'major-mode (buffer-local-variables)))
- 'emacs-lisp-mode)
+ (derived-mode-p 'emacs-lisp-mode)
(setq bytecomp-file-name (file-name-nondirectory bytecomp-file)
bytecomp-file-dir (file-name-directory bytecomp-file)))
(list (read-file-name (if current-prefix-arg
;; within byte-compile-from-buffer lingers in that buffer.
(setq output-buffer
(save-current-buffer
- (byte-compile-from-buffer input-buffer bytecomp-filename)))
+ (byte-compile-from-buffer input-buffer)))
(if byte-compiler-error-flag
nil
(when byte-compile-verbose
(insert "\n"))
((message "%s" (prin1-to-string value)))))))
+;; Dynamically bound in byte-compile-from-buffer.
+;; NB also used in cl.el and cl-macs.el.
+(defvar bytecomp-outbuffer)
-(defun byte-compile-from-buffer (bytecomp-inbuffer &optional bytecomp-filename)
- ;; Filename is used for the loading-into-Emacs-18 error message.
+(defun byte-compile-from-buffer (bytecomp-inbuffer)
(let (bytecomp-outbuffer
(byte-compile-current-buffer bytecomp-inbuffer)
(byte-compile-read-position nil)
(setq case-fold-search nil))
(displaying-byte-compile-warnings
(with-current-buffer bytecomp-inbuffer
- (and bytecomp-filename
- (byte-compile-insert-header bytecomp-filename bytecomp-outbuffer))
+ (and byte-compile-current-file
+ (byte-compile-insert-header byte-compile-current-file
+ bytecomp-outbuffer))
(goto-char (point-min))
;; Should we always do this? When calling multiple files, it
;; would be useful to delay this warning until all have been
(byte-compile-warn "!! The file uses old-style backquotes !!
This functionality has been obsolete for more than 10 years already
and will be removed soon. See (elisp)Backquote in the manual."))
- (byte-compile-file-form form)))
+ (byte-compile-toplevel-file-form form)))
;; Compile pending forms at end of file.
(byte-compile-flush-pending)
;; Make warnings about unresolved functions
(byte-compile-warn-about-unresolved-functions))
;; Fix up the header at the front of the output
;; if the buffer contains multibyte characters.
- (and bytecomp-filename
+ (and byte-compile-current-file
(with-current-buffer bytecomp-outbuffer
- (byte-compile-fix-header bytecomp-filename)))))
+ (byte-compile-fix-header byte-compile-current-file)))))
bytecomp-outbuffer))
(defun byte-compile-fix-header (filename)
";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n"))))
-;; Dynamically bound in byte-compile-from-buffer.
-;; NB also used in cl.el and cl-macs.el.
-(defvar bytecomp-outbuffer)
-
(defun byte-compile-output-file-form (form)
;; writes the given form to the output buffer, being careful of docstrings
;; in defun, defmacro, defvar, defvaralias, defconst, autoload and
;; defalias calls are output directly by byte-compile-file-form-defmumble;
;; it does not pay to first build the defalias in defmumble and then parse
;; it here.
- (if (and (memq (car-safe form) '(defun defmacro defvar defvaralias defconst autoload
- custom-declare-variable))
+ (if (and (memq (car-safe form) '(defun defmacro defvar defvaralias defconst
+ autoload custom-declare-variable))
(stringp (nth 3 form)))
(byte-compile-output-docform nil nil '("\n(" 3 ")") form nil
(memq (car form)
nil)))
(defvar print-gensym-alist) ;Used before print-circle existed.
+(defvar for-effect)
(defun byte-compile-output-docform (preface name info form specindex quoted)
"Print a form with a doc string. INFO is (prefix doc-index postfix).
;; to objects already output
;; (for instance, gensyms in the arg list).
(let (non-nil)
- (dotimes (i (length print-number-table))
- (if (aref print-number-table i)
- (setq non-nil t)))
+ (when (hash-table-p print-number-table)
+ (maphash (lambda (_k v) (if v (setq non-nil t)))
+ print-number-table))
(not non-nil)))
;; Output the byte code and constants specially
;; for lazy dynamic loading.
byte-compile-maxdepth 0
byte-compile-output nil))))
-(defun byte-compile-file-form (form)
- (let ((byte-compile-current-form nil) ; close over this for warnings.
- bytecomp-handler)
+;; byte-hunk-handlers cannot call this!
+(defun byte-compile-toplevel-file-form (form)
+ (let ((byte-compile-current-form nil)) ; close over this for warnings.
(setq form (macroexpand-all form byte-compile-macro-environment))
- (cond ((not (consp form))
- (byte-compile-keep-pending form))
- ((and (symbolp (car form))
+ (if lexical-binding
+ (setq form (cconv-closure-convert form)))
+ (byte-compile-file-form form)))
+
+;; byte-hunk-handlers can call this.
+(defun byte-compile-file-form (form)
+ (let (bytecomp-handler)
+ (cond ((and (consp form)
+ (symbolp (car form))
(setq bytecomp-handler (get (car form) 'byte-hunk-handler)))
(cond ((setq form (funcall bytecomp-handler form))
(byte-compile-flush-pending)
;; so make-docfile can recognise them. Most other things can be output
;; as byte-code.
-(put 'defsubst 'byte-hunk-handler 'byte-compile-file-form-defsubst)
-(defun byte-compile-file-form-defsubst (form)
- (when (assq (nth 1 form) byte-compile-unresolved-functions)
- (setq byte-compile-current-form (nth 1 form))
- (byte-compile-warn "defsubst `%s' was used before it was defined"
- (nth 1 form)))
- (byte-compile-file-form form)
- ;; Return nil so the form is not output twice.
- nil)
-
(put 'autoload 'byte-hunk-handler 'byte-compile-file-form-autoload)
(defun byte-compile-file-form-autoload (form)
(and (let ((form form))
(if (byte-compile-warning-enabled-p 'redefine)
(byte-compile-arglist-warn form macrop))
(if byte-compile-verbose
- ;; bytecomp-filename is from byte-compile-from-buffer.
- (message "Compiling %s... (%s)" (or bytecomp-filename "") (nth 1 form)))
+ (message "Compiling %s... (%s)"
+ (or byte-compile-current-file "") (nth 1 form)))
(cond (bytecomp-that-one
(if (and (byte-compile-warning-enabled-p 'redefine)
;; don't warn when compiling the stubs in byte-run...
(if macro
(setq fun (cdr fun)))
(cond ((eq (car-safe fun) 'lambda)
- ;; expand macros
- (setq fun
- (macroexpand-all fun
- byte-compile-initial-macro-environment))
- ;; get rid of the `function' quote added by the `lambda' macro
- (setq fun (cadr fun))
+ ;; Expand macros.
+ (setq fun
+ (macroexpand-all fun
+ byte-compile-initial-macro-environment))
+ (if lexical-binding
+ (setq fun (cconv-closure-convert fun)))
+ ;; Get rid of the `function' quote added by the `lambda' macro.
+ (if (eq (car-safe fun) 'function) (setq fun (cadr fun)))
(setq fun (if macro
(cons 'macro (byte-compile-lambda fun))
(byte-compile-lambda fun)))
;; b-c-lambda didn't produce a compiled-function, so it's either a trivial
;; function, or this is Emacs 18, or generate-emacs19-bytecodes is off.
((let (tmp)
+ ;; FIXME: can this happen?
(if (and (setq tmp (assq 'byte-code (cdr-safe (cdr fun))))
(null (cdr (memq tmp fun))))
;; Generate a make-byte-code call.
(list 'quote fun))))))
;; Turn a function into an ordinary lambda. Needed for v18 files.
-(defun byte-compile-byte-code-unmake (function)
+(defun byte-compile-byte-code-unmake (function) ;FIXME: what is it?
(if (consp function)
function;;It already is a lambda.
(setq function (append function nil)) ; turn it into a list
(setq list (cdr list)))))
-(autoload 'byte-compile-make-lambda-lexenv "byte-lexbind")
+(defun byte-compile-arglist-vars (arglist)
+ "Return a list of the variables in the lambda argument list ARGLIST."
+ (remq '&rest (remq '&optional arglist)))
+
+(defun byte-compile-make-lambda-lexenv (form)
+ "Return a new lexical environment for a lambda expression FORM."
+ ;; See if this is a closure or not
+ (let ((args (byte-compile-arglist-vars (cadr form))))
+ (let ((lexenv nil))
+ ;; Fill in the initial stack contents
+ (let ((stackpos 0))
+ ;; Add entries for each argument
+ (dolist (arg args)
+ (push (cons arg stackpos) lexenv)
+ (setq stackpos (1+ stackpos)))
+ ;; Return the new lexical environment
+ lexenv))))
+
+(defun byte-compile-make-args-desc (arglist)
+ (let ((mandatory 0)
+ nonrest (rest 0))
+ (while (and arglist (not (memq (car arglist) '(&optional &rest))))
+ (setq mandatory (1+ mandatory))
+ (setq arglist (cdr arglist)))
+ (setq nonrest mandatory)
+ (when (eq (car arglist) '&optional)
+ (setq arglist (cdr arglist))
+ (while (and arglist (not (eq (car arglist) '&rest)))
+ (setq nonrest (1+ nonrest))
+ (setq arglist (cdr arglist))))
+ (when arglist
+ (setq rest 1))
+ (if (> mandatory 127)
+ (byte-compile-report-error "Too many (>127) mandatory arguments")
+ (logior mandatory
+ (lsh nonrest 8)
+ (lsh rest 7)))))
;; Byte-compile a lambda-expression and return a valid function.
;; The value is usually a compiled function but may be the original
;; of the list FUN and `byte-compile-set-symbol-position' is not called.
;; Use this feature to avoid calling `byte-compile-set-symbol-position'
;; for symbols generated by the byte compiler itself.
-(defun byte-compile-lambda (bytecomp-fun &optional add-lambda)
+(defun byte-compile-lambda (bytecomp-fun &optional add-lambda reserved-csts)
(if add-lambda
(setq bytecomp-fun (cons 'lambda bytecomp-fun))
(unless (eq 'lambda (car-safe bytecomp-fun))
(byte-compile-check-lambda-list (nth 1 bytecomp-fun))
(let* ((bytecomp-arglist (nth 1 bytecomp-fun))
(byte-compile-bound-variables
- (nconc (and (byte-compile-warning-enabled-p 'free-vars)
- (delq '&rest
- (delq '&optional (copy-sequence bytecomp-arglist))))
- byte-compile-bound-variables))
+ (append (and (not lexical-binding)
+ (byte-compile-arglist-vars bytecomp-arglist))
+ byte-compile-bound-variables))
(bytecomp-body (cdr (cdr bytecomp-fun)))
(bytecomp-doc (if (stringp (car bytecomp-body))
- (prog1 (car bytecomp-body)
- ;; Discard the doc string
- ;; unless it is the last element of the body.
- (if (cdr bytecomp-body)
- (setq bytecomp-body (cdr bytecomp-body))))))
+ (prog1 (car bytecomp-body)
+ ;; Discard the doc string
+ ;; unless it is the last element of the body.
+ (if (cdr bytecomp-body)
+ (setq bytecomp-body (cdr bytecomp-body))))))
(bytecomp-int (assq 'interactive bytecomp-body)))
;; Process the interactive spec.
(when bytecomp-int
;; compile it, because `call-interactively' looks at the
;; args of `list'. Actually, compile it to get warnings,
;; but don't use the result.
- (let ((form (nth 1 bytecomp-int)))
+ (let* ((form (nth 1 bytecomp-int))
+ (newform (byte-compile-top-level form)))
(while (memq (car-safe form) '(let let* progn save-excursion))
(while (consp (cdr form))
(setq form (cdr form)))
(setq form (car form)))
- (if (eq (car-safe form) 'list)
- (byte-compile-top-level (nth 1 bytecomp-int))
- (setq bytecomp-int (list 'interactive
- (byte-compile-top-level
- (nth 1 bytecomp-int)))))))
+ (if (and (eq (car-safe form) 'list)
+ ;; The spec is evaled in callint.c in dynamic-scoping
+ ;; mode, so just leaving the form unchanged would mean
+ ;; it won't be eval'd in the right mode.
+ (not lexical-binding))
+ nil
+ (setq bytecomp-int `(interactive ,newform)))))
((cdr bytecomp-int)
(byte-compile-warn "malformed interactive spec: %s"
(prin1-to-string bytecomp-int)))))
;; Process the body.
- (let* ((byte-compile-lexical-environment
- ;; If doing lexical binding, push a new lexical environment
- ;; containing the args and any closed-over variables.
- (and lexical-binding
- (byte-compile-make-lambda-lexenv
- fun
- byte-compile-lexical-environment)))
- (is-closure
- ;; This is true if we should be making a closure instead of
- ;; a simple lambda (because some variables from the
- ;; containing lexical environment are closed over).
- (and lexical-binding
- (byte-compile-closure-initial-lexenv-p
- byte-compile-lexical-environment)))
- (byte-compile-current-heap-environment nil)
- (byte-compile-current-num-closures 0)
- (compiled
- (byte-compile-top-level (cons 'progn bytecomp-body) nil 'lambda)))
+ (let ((compiled
+ (byte-compile-top-level (cons 'progn bytecomp-body) nil 'lambda
+ ;; If doing lexical binding, push a new
+ ;; lexical environment containing just the
+ ;; args (since lambda expressions should be
+ ;; closed by now).
+ (and lexical-binding
+ (byte-compile-make-lambda-lexenv
+ bytecomp-fun))
+ reserved-csts)))
;; Build the actual byte-coded function.
(if (eq 'byte-code (car-safe compiled))
- (let ((code
- (apply 'make-byte-code
- (append (list bytecomp-arglist)
- ;; byte-string, constants-vector, stack depth
- (cdr compiled)
- ;; optionally, the doc string.
- (if (or bytecomp-doc bytecomp-int
- lexical-binding)
- (list bytecomp-doc))
- ;; optionally, the interactive spec.
- (if (or bytecomp-int lexical-binding)
- (list (nth 1 bytecomp-int)))
- (if lexical-binding
- '(t))))))
- (if is-closure
- (cons 'closure code)
- code))
+ (apply 'make-byte-code
+ (if lexical-binding
+ (byte-compile-make-args-desc bytecomp-arglist)
+ bytecomp-arglist)
+ (append
+ ;; byte-string, constants-vector, stack depth
+ (cdr compiled)
+ ;; optionally, the doc string.
+ (cond (lexical-binding
+ (require 'help-fns)
+ (list (help-add-fundoc-usage
+ bytecomp-doc bytecomp-arglist)))
+ ((or bytecomp-doc bytecomp-int)
+ (list bytecomp-doc)))
+ ;; optionally, the interactive spec.
+ (if bytecomp-int
+ (list (nth 1 bytecomp-int)))))
(setq compiled
(nconc (if bytecomp-int (list bytecomp-int))
(cond ((eq (car-safe compiled) 'progn) (cdr compiled))
(bytecomp-body (list nil))))
compiled))))))
-(defun byte-compile-closure-code-p (code)
- (eq (car-safe code) 'closure))
-
-(defun byte-compile-make-closure (code)
- ;; A real closure requires that the constant be curried with an
- ;; environment vector to make a closure object.
- (if for-effect
- (setq for-effect nil)
- (byte-compile-push-constant 'curry)
- (byte-compile-push-constant code)
- (byte-compile-lexical-variable-ref byte-compile-current-heap-environment)
- (byte-compile-out 'byte-call 2)))
-
(defun byte-compile-closure (form &optional add-lambda)
(let ((code (byte-compile-lambda form add-lambda)))
- (if (byte-compile-closure-code-p code)
- (byte-compile-make-closure code)
- ;; A simple lambda is just a constant
- (byte-compile-constant code))))
+ ;; A simple lambda is just a constant.
+ (byte-compile-constant code)))
+
+(defvar byte-compile-reserved-constants 0)
(defun byte-compile-constants-vector ()
;; Builds the constants-vector from the current variables and constants.
;; Next up to byte-constant-limit are constants, still with one-byte codes.
;; Next variables again, to get 2-byte codes for variable lookup.
;; The rest of the constants and variables need 3-byte byte-codes.
- (let* ((i -1)
+ (let* ((i (1- byte-compile-reserved-constants))
(rest (nreverse byte-compile-variables)) ; nreverse because the first
(other (nreverse byte-compile-constants)) ; vars often are used most.
ret tmp
limit)
(while (or rest other)
(setq limit (car limits))
- (while (and rest (not (eq i limit)))
- (if (setq tmp (assq (car (car rest)) ret))
- (setcdr (car rest) (cdr tmp))
+ (while (and rest (< i limit))
+ (cond
+ ((numberp (car rest))
+ (assert (< (car rest) byte-compile-reserved-constants)))
+ ((setq tmp (assq (car (car rest)) ret))
+ (setcdr (car rest) (cdr tmp)))
+ (t
(setcdr (car rest) (setq i (1+ i)))
- (setq ret (cons (car rest) ret)))
+ (setq ret (cons (car rest) ret))))
(setq rest (cdr rest)))
(setq limits (cdr limits)
rest (prog1 other
;; Given an expression FORM, compile it and return an equivalent byte-code
;; expression (a call to the function byte-code).
-(defun byte-compile-top-level (form &optional for-effect output-type)
+(defun byte-compile-top-level (form &optional for-effect-arg output-type
+ lexenv reserved-csts)
;; OUTPUT-TYPE advises about how form is expected to be used:
;; 'eval or nil -> a single form,
;; 'progn or t -> a list of forms,
;; 'lambda -> body of a lambda,
;; 'file -> used at file-level.
- (let ((byte-compile-constants nil)
+ (let ((for-effect for-effect-arg)
+ (byte-compile-constants nil)
(byte-compile-variables nil)
(byte-compile-tag-number 0)
(byte-compile-depth 0)
(byte-compile-maxdepth 0)
+ (byte-compile-lexical-environment lexenv)
+ (byte-compile-reserved-constants (or reserved-csts 0))
(byte-compile-output nil))
(if (memq byte-optimize '(t source))
(setq form (byte-optimize-form form for-effect)))
(stringp (nth 1 form)) (vectorp (nth 2 form))
(natnump (nth 3 form)))
form
- ;; Set up things for a lexically-bound function
+ ;; Set up things for a lexically-bound function.
(when (and lexical-binding (eq output-type 'lambda))
;; See how many arguments there are, and set the current stack depth
- ;; accordingly
- (dolist (var byte-compile-lexical-environment)
- (when (byte-compile-lexvar-on-stack-p var)
- (setq byte-compile-depth (1+ byte-compile-depth))))
+ ;; accordingly.
+ (setq byte-compile-depth (length byte-compile-lexical-environment))
;; If there are args, output a tag to record the initial
- ;; stack-depth for the optimizer
+ ;; stack-depth for the optimizer.
(when (> byte-compile-depth 0)
- (byte-compile-out-tag (byte-compile-make-tag)))
- ;; If this is the top-level of a lexically bound lambda expression,
- ;; perhaps some parameters on stack need to be copied into a heap
- ;; environment, so check for them, and do so if necessary.
- (let ((lforminfo (byte-compile-make-lforminfo)))
- ;; Add any lexical variable that's on the stack to the analysis set.
- (dolist (var byte-compile-lexical-environment)
- (when (byte-compile-lexvar-on-stack-p var)
- (byte-compile-lforminfo-add-var lforminfo (car var) t)))
- ;; Analyze the body
- (unless (null (byte-compile-lforminfo-vars lforminfo))
- (byte-compile-lforminfo-analyze lforminfo form nil nil))
- ;; If the analysis revealed some argument need to be in a heap
- ;; environment (because they're closed over by an embedded
- ;; lambda), put them there.
- (setq byte-compile-lexical-environment
- (nconc (byte-compile-maybe-push-heap-environment lforminfo)
- byte-compile-lexical-environment))
- (dolist (arginfo (byte-compile-lforminfo-vars lforminfo))
- (when (byte-compile-lvarinfo-closed-over-p arginfo)
- (byte-compile-bind (car arginfo)
- byte-compile-lexical-environment
- lforminfo)))))
+ (byte-compile-out-tag (byte-compile-make-tag))))
;; Now compile FORM
(byte-compile-form form for-effect)
(byte-compile-out-toplevel for-effect output-type))))
-(defun byte-compile-out-toplevel (&optional for-effect output-type)
- (if for-effect
+(defun byte-compile-out-toplevel (&optional for-effect-arg output-type)
+ (if for-effect-arg
;; The stack is empty. Push a value to be returned from (byte-code ..).
(if (eq (car (car byte-compile-output)) 'byte-discard)
(setq byte-compile-output (cdr byte-compile-output))
(setq byte-compile-output (nreverse byte-compile-output))
(if (memq byte-optimize '(t byte))
(setq byte-compile-output
- (byte-optimize-lapcode byte-compile-output for-effect)))
+ (byte-optimize-lapcode byte-compile-output)))
;; Decompile trivial functions:
;; only constants and variables, or a single funcall except in lambdas.
;; progn -> as <<same-as-eval>> or (progn <<same-as-eval>> atom)
;; file -> as progn, but takes both quotes and atoms, and longer forms.
(let (rest
+ (for-effect for-effect-arg)
(maycall (not (eq output-type 'lambda))) ; t if we may make a funcall.
tmp body)
(cond
((car body)))))
;; Given BYTECOMP-BODY, compile it and return a new body.
-(defun byte-compile-top-level-body (bytecomp-body &optional for-effect)
+(defun byte-compile-top-level-body (bytecomp-body &optional for-effect-arg)
(setq bytecomp-body
- (byte-compile-top-level (cons 'progn bytecomp-body) for-effect t))
+ (byte-compile-top-level (cons 'progn bytecomp-body) for-effect-arg t))
(cond ((eq (car-safe bytecomp-body) 'progn)
(cdr bytecomp-body))
(bytecomp-body
(list bytecomp-body))))
-(put 'declare-function 'byte-hunk-handler 'byte-compile-declare-function)
-(defun byte-compile-declare-function (form)
- (push (cons (nth 1 form)
- (if (and (> (length form) 3)
- (listp (nth 3 form)))
- (list 'declared (nth 3 form))
+;; Special macro-expander used during byte-compilation.
+(defun byte-compile-macroexpand-declare-function (fn file &rest args)
+ (push (cons fn
+ (if (and (consp args) (listp (car args)))
+ (list 'declared (car args))
t)) ; arglist not specified
byte-compile-function-environment)
;; We are stating that it _will_ be defined at runtime.
(setq byte-compile-noruntime-functions
- (delq (nth 1 form) byte-compile-noruntime-functions))
- nil)
+ (delq fn byte-compile-noruntime-functions))
+ ;; Delegate the rest to the normal macro definition.
+ (macroexpand `(declare-function ,fn ,file ,@args)))
\f
;; This is the recursive entry point for compiling each subform of an
;; byte-compile-form, or take extreme care to handle for-effect correctly.
;; (Use byte-compile-form-do-effect to reset the for-effect flag too.)
;;
-(defun byte-compile-form (form &optional for-effect)
- (cond ((not (consp form))
- (cond ((or (not (symbolp form)) (byte-compile-const-symbol-p form))
- (when (symbolp form)
- (byte-compile-set-symbol-position form))
- (byte-compile-constant form))
- ((and for-effect byte-compile-delete-errors)
- (when (symbolp form)
- (byte-compile-set-symbol-position form))
- (setq for-effect nil))
- (t
- (byte-compile-variable-ref form))))
- ((symbolp (car form))
- (let* ((bytecomp-fn (car form))
- (bytecomp-handler (get bytecomp-fn 'byte-compile)))
- (when (byte-compile-const-symbol-p bytecomp-fn)
- (byte-compile-warn "`%s' called as a function" bytecomp-fn))
- (and (byte-compile-warning-enabled-p 'interactive-only)
- (memq bytecomp-fn byte-compile-interactive-only-functions)
- (byte-compile-warn "`%s' used from Lisp code\n\
+(defun byte-compile-form (form &optional for-effect-arg)
+ (let ((for-effect for-effect-arg))
+ (cond
+ ((not (consp form))
+ (cond ((or (not (symbolp form)) (byte-compile-const-symbol-p form))
+ (when (symbolp form)
+ (byte-compile-set-symbol-position form))
+ (byte-compile-constant form))
+ ((and for-effect byte-compile-delete-errors)
+ (when (symbolp form)
+ (byte-compile-set-symbol-position form))
+ (setq for-effect nil))
+ (t
+ (byte-compile-variable-ref form))))
+ ((symbolp (car form))
+ (let* ((bytecomp-fn (car form))
+ (bytecomp-handler (get bytecomp-fn 'byte-compile)))
+ (when (byte-compile-const-symbol-p bytecomp-fn)
+ (byte-compile-warn "`%s' called as a function" bytecomp-fn))
+ (and (byte-compile-warning-enabled-p 'interactive-only)
+ (memq bytecomp-fn byte-compile-interactive-only-functions)
+ (byte-compile-warn "`%s' used from Lisp code\n\
That command is designed for interactive use only" bytecomp-fn))
- (when (byte-compile-warning-enabled-p 'callargs)
- (if (memq bytecomp-fn
- '(custom-declare-group custom-declare-variable
- custom-declare-face))
- (byte-compile-nogroup-warn form))
- (byte-compile-callargs-warn form))
- (if (and bytecomp-handler
- ;; Make sure that function exists. This is important
- ;; for CL compiler macros since the symbol may be
- ;; `cl-byte-compile-compiler-macro' but if CL isn't
- ;; loaded, this function doesn't exist.
- (or (not (memq bytecomp-handler
- '(cl-byte-compile-compiler-macro)))
- (functionp bytecomp-handler)))
- (funcall bytecomp-handler form)
- (byte-compile-normal-call form))
- (if (byte-compile-warning-enabled-p 'cl-functions)
- (byte-compile-cl-warn form))))
- ((and (or (byte-code-function-p (car form))
- (eq (car-safe (car form)) 'lambda))
- ;; if the form comes out the same way it went in, that's
- ;; because it was malformed, and we couldn't unfold it.
- (not (eq form (setq form (byte-compile-unfold-lambda form)))))
- (byte-compile-form form for-effect)
- (setq for-effect nil))
- ((byte-compile-normal-call form)))
- (if for-effect
- (byte-compile-discard)))
+ (if (and (fboundp (car form))
+ (eq (car-safe (symbol-function (car form))) 'macro))
+ (byte-compile-report-error
+ (format "Forgot to expand macro %s" (car form))))
+ (if (and bytecomp-handler
+ ;; Make sure that function exists. This is important
+ ;; for CL compiler macros since the symbol may be
+ ;; `cl-byte-compile-compiler-macro' but if CL isn't
+ ;; loaded, this function doesn't exist.
+ (and (not (eq bytecomp-handler
+ ;; Already handled by macroexpand-all.
+ 'cl-byte-compile-compiler-macro))
+ (functionp bytecomp-handler)))
+ (funcall bytecomp-handler form)
+ (byte-compile-normal-call form))
+ (if (byte-compile-warning-enabled-p 'cl-functions)
+ (byte-compile-cl-warn form))))
+ ((and (or (byte-code-function-p (car form))
+ (eq (car-safe (car form)) 'lambda))
+ ;; if the form comes out the same way it went in, that's
+ ;; because it was malformed, and we couldn't unfold it.
+ (not (eq form (setq form (byte-compile-unfold-lambda form)))))
+ (byte-compile-form form for-effect)
+ (setq for-effect nil))
+ ((byte-compile-normal-call form)))
+ (if for-effect
+ (byte-compile-discard))))
(defun byte-compile-normal-call (form)
+ (when (and (byte-compile-warning-enabled-p 'callargs)
+ (symbolp (car form)))
+ (if (memq (car form)
+ '(custom-declare-group
+ ;; custom-declare-variable custom-declare-face
+ ))
+ (byte-compile-nogroup-warn form))
+ (when (get (car form) 'byte-obsolete-info)
+ (byte-compile-warn-obsolete (car form)))
+ (byte-compile-callargs-warn form))
(if byte-compile-generate-call-tree
(byte-compile-annotate-call-tree form))
(when (and for-effect (eq (car form) 'mapcar)
(defun byte-compile-dynamic-variable-bind (var)
"Generate code to bind the lexical variable VAR to the top-of-stack value."
(byte-compile-check-variable var t)
- (when (byte-compile-warning-enabled-p 'free-vars)
- (push var byte-compile-bound-variables))
+ (push var byte-compile-bound-variables)
(byte-compile-dynamic-variable-op 'byte-varbind var))
-;; This is used when it's know that VAR _definitely_ has a lexical
-;; binding, and no error-checking should be done.
-(defun byte-compile-lexical-variable-ref (var)
- "Generate code to push the value of the lexical variable VAR on the stack."
- (let ((binding (assq var byte-compile-lexical-environment)))
- (when (null binding)
- (error "Lexical binding not found for `%s'" var))
- (if (byte-compile-lexvar-on-stack-p binding)
- ;; On the stack
- (byte-compile-stack-ref (byte-compile-lexvar-offset binding))
- ;; In a heap environment vector; first push the vector on the stack
- (byte-compile-lexical-variable-ref
- (byte-compile-lexvar-environment binding))
- ;; Now get the value from it
- (byte-compile-out 'byte-vec-ref (byte-compile-lexvar-offset binding)))))
-
(defun byte-compile-variable-ref (var)
"Generate code to push the value of the variable VAR on the stack."
(byte-compile-check-variable var)
(let ((lex-binding (assq var byte-compile-lexical-environment)))
(if lex-binding
;; VAR is lexically bound
- (if (byte-compile-lexvar-on-stack-p lex-binding)
- ;; On the stack
- (byte-compile-stack-ref (byte-compile-lexvar-offset lex-binding))
- ;; In a heap environment vector
- (byte-compile-lexical-variable-ref
- (byte-compile-lexvar-environment lex-binding))
- (byte-compile-out 'byte-vec-ref
- (byte-compile-lexvar-offset lex-binding)))
+ (byte-compile-stack-ref (cdr lex-binding))
;; VAR is dynamically bound
(unless (or (not (byte-compile-warning-enabled-p 'free-vars))
(boundp var)
(memq var byte-compile-bound-variables)
(memq var byte-compile-free-references))
- (byte-compile-warn "reference to free variable `%s'" var)
+ (byte-compile-warn "reference to free variable `%S'" var)
(push var byte-compile-free-references))
(byte-compile-dynamic-variable-op 'byte-varref var))))
(let ((lex-binding (assq var byte-compile-lexical-environment)))
(if lex-binding
;; VAR is lexically bound
- (if (byte-compile-lexvar-on-stack-p lex-binding)
- ;; On the stack
- (byte-compile-stack-set (byte-compile-lexvar-offset lex-binding))
- ;; In a heap environment vector
- (byte-compile-lexical-variable-ref
- (byte-compile-lexvar-environment lex-binding))
- (byte-compile-out 'byte-vec-set
- (byte-compile-lexvar-offset lex-binding)))
+ (byte-compile-stack-set (cdr lex-binding))
;; VAR is dynamically bound
(unless (or (not (byte-compile-warning-enabled-p 'free-vars))
(boundp var)
(defun byte-compile-push-constant (const)
(let ((for-effect nil))
(inline (byte-compile-constant const))))
-
-(defun byte-compile-push-unknown-constant (&optional id)
- "Generate code to push a `constant' who's value isn't known yet.
-A tag is returned which may then later be passed to
-`byte-compile-resolve-unknown-constant' to finalize the value.
-The optional argument ID is a tag returned by an earlier call to
-`byte-compile-push-unknown-constant', in which case the same constant is
-pushed again."
- (unless id
- (setq id (list (make-symbol "unknown")))
- (push id byte-compile-constants))
- (byte-compile-out 'byte-constant id)
- id)
-
-(defun byte-compile-resolve-unknown-constant (id value)
- "Give an `unknown constant' a value.
-ID is the tag returned by `byte-compile-push-unknown-constant'. and VALUE
-is the value it should have."
- (setcar id value))
-
\f
;; Compile those primitive ordinary functions
;; which have special byte codes just for speed.
(byte-defop-compiler bobp 0)
(byte-defop-compiler current-buffer 0)
;;(byte-defop-compiler read-char 0) ;; obsolete
-(byte-defop-compiler interactive-p 0)
(byte-defop-compiler widen 0)
(byte-defop-compiler end-of-line 0-1)
(byte-defop-compiler forward-char 0-1)
((= len 4) (byte-compile-three-args form))
(t (byte-compile-subr-wrong-args form "2-3")))))
-(defun byte-compile-noop (form)
+(defun byte-compile-noop (_form)
(byte-compile-constant nil))
(defun byte-compile-discard (&optional num preserve-tos)
(defun byte-compile-stack-ref (stack-pos)
"Output byte codes to push the value at position STACK-POS in the stack, on the top of the stack."
- (if (= byte-compile-depth (1+ stack-pos))
- ;; A simple optimization
- (byte-compile-out 'byte-dup)
- ;; normal case
- (byte-compile-out 'byte-stack-ref stack-pos)))
+ (let ((dist (- byte-compile-depth (1+ stack-pos))))
+ (if (zerop dist)
+ ;; A simple optimization
+ (byte-compile-out 'byte-dup)
+ ;; normal case
+ (byte-compile-out 'byte-stack-ref dist))))
(defun byte-compile-stack-set (stack-pos)
"Output byte codes to store the top-of-stack value at position STACK-POS in the stack."
- (byte-compile-out 'byte-stack-set stack-pos))
-
+ (byte-compile-out 'byte-stack-set (- byte-compile-depth (1+ stack-pos))))
+
+(byte-defop-compiler-1 internal-make-closure byte-compile-make-closure)
+(byte-defop-compiler-1 internal-get-closed-var byte-compile-get-closed-var)
+
+(defconst byte-compile--env-var (make-symbol "env"))
+
+(defun byte-compile-make-closure (form)
+ (if for-effect (setq for-effect nil)
+ (let* ((vars (nth 1 form))
+ (env (nth 2 form))
+ (body (nthcdr 3 form))
+ (fun
+ (byte-compile-lambda `(lambda ,vars . ,body) nil (length env))))
+ (assert (byte-code-function-p fun))
+ (byte-compile-form `(make-byte-code
+ ',(aref fun 0) ',(aref fun 1)
+ (vconcat (vector . ,env) ',(aref fun 2))
+ ,@(nthcdr 3 (mapcar (lambda (x) `',x) fun)))))))
+
+
+(defun byte-compile-get-closed-var (form)
+ (if for-effect (setq for-effect nil)
+ (byte-compile-out 'byte-constant ;; byte-closed-var
+ (nth 1 form))))
;; Compile a function that accepts one or more args and is right-associative.
;; We do it by left-associativity so that the operations
(byte-defop-compiler-1 setq)
(byte-defop-compiler-1 setq-default)
(byte-defop-compiler-1 quote)
-(byte-defop-compiler-1 quote-form)
(defun byte-compile-setq (form)
(let ((bytecomp-args (cdr form)))
(defun byte-compile-quote (form)
(byte-compile-constant (car (cdr form))))
-
-(defun byte-compile-quote-form (form)
- (byte-compile-constant (byte-compile-top-level (nth 1 form))))
-
\f
;;; control structures
-(defun byte-compile-body (bytecomp-body &optional for-effect)
+(defun byte-compile-body (bytecomp-body &optional for-effect-arg)
(while (cdr bytecomp-body)
(byte-compile-form (car bytecomp-body) t)
(setq bytecomp-body (cdr bytecomp-body)))
- (byte-compile-form (car bytecomp-body) for-effect))
+ (byte-compile-form (car bytecomp-body) for-effect-arg))
(defsubst byte-compile-body-do-effect (bytecomp-body)
(byte-compile-body bytecomp-body for-effect)
(byte-defop-compiler-1 while)
(byte-defop-compiler-1 funcall)
(byte-defop-compiler-1 let)
-(byte-defop-compiler-1 let*)
+(byte-defop-compiler-1 let* byte-compile-let)
(defun byte-compile-progn (form)
(byte-compile-body-do-effect (cdr form)))
,condition (list 'boundp 'default-boundp)))
;; Maybe add to the bound list.
(byte-compile-bound-variables
- (if bound-list
- (append bound-list byte-compile-bound-variables)
- byte-compile-bound-variables)))
+ (append bound-list byte-compile-bound-variables)))
(unwind-protect
;; If things not being bound at all is ok, so must them being obsolete.
;; Note that we add to the existing lists since Tramp (ab)uses
(defun byte-compile-while (form)
(let ((endtag (byte-compile-make-tag))
- (looptag (byte-compile-make-tag))
- ;; Heap environments can't be shared between a loop and its
- ;; enclosing environment (because any lexical variables bound
- ;; inside the loop should have an independent value for each
- ;; iteration). Setting `byte-compile-current-num-closures' to
- ;; an invalid value causes the code that tries to merge
- ;; environments to not do so.
- (byte-compile-current-num-closures -1))
+ (looptag (byte-compile-make-tag)))
(byte-compile-out-tag looptag)
(byte-compile-form (car (cdr form)))
(byte-compile-goto-if nil for-effect endtag)
\f
;; let binding
-;; All other lexical-binding functions are guarded by a non-nil return
-;; value from `byte-compile-compute-lforminfo', so they needn't be
-;; autoloaded.
-(autoload 'byte-compile-compute-lforminfo "byte-lexbind")
-
-(defun byte-compile-push-binding-init (clause init-lexenv lforminfo)
+(defun byte-compile-push-binding-init (clause)
"Emit byte-codes to push the initialization value for CLAUSE on the stack.
-INIT-LEXENV is the lexical environment created for initializations
-already done for this form.
-LFORMINFO should be information about lexical variables being bound.
-Return INIT-LEXENV updated to include the newest initialization, or nil
-if LFORMINFO is nil (meaning all bindings are dynamic)."
- (let* ((var (if (consp clause) (car clause) clause))
- (vinfo
- (and lforminfo (assq var (byte-compile-lforminfo-vars lforminfo))))
- (unused (and vinfo (zerop (cadr vinfo)))))
- (unless (and unused (symbolp clause))
- (when (and lforminfo (not unused))
- ;; We record the stack position even of dynamic bindings and
- ;; variables in non-stack lexical environments; we'll put
- ;; them in the proper place below.
- (push (byte-compile-make-lexvar var byte-compile-depth) init-lexenv))
+Return the offset in the form (VAR . OFFSET)."
+ (let* ((var (if (consp clause) (car clause) clause)))
+ ;; We record the stack position even of dynamic bindings and
+ ;; variables in non-stack lexical environments; we'll put
+ ;; them in the proper place below.
+ (prog1 (cons var byte-compile-depth)
(if (consp clause)
- (byte-compile-form (cadr clause) unused)
- (byte-compile-push-constant nil))))
- init-lexenv)
+ (byte-compile-form (cadr clause))
+ (byte-compile-push-constant nil)))))
+
+(defun byte-compile-not-lexical-var-p (var)
+ (or (not (symbolp var))
+ (special-variable-p var)
+ (memq var byte-compile-bound-variables)
+ (memq var '(nil t))
+ (keywordp var)))
+
+(defun byte-compile-bind (var init-lexenv)
+ "Emit byte-codes to bind VAR and update `byte-compile-lexical-environment'.
+INIT-LEXENV should be a lexical-environment alist describing the
+positions of the init value that have been pushed on the stack.
+Return non-nil if the TOS value was popped."
+ ;; The presence of lexical bindings mean that we may have to
+ ;; juggle things on the stack, to move them to TOS for
+ ;; dynamic binding.
+ (cond ((not (byte-compile-not-lexical-var-p var))
+ ;; VAR is a simple stack-allocated lexical variable
+ (push (assq var init-lexenv)
+ byte-compile-lexical-environment)
+ nil)
+ ((eq var (caar init-lexenv))
+ ;; VAR is dynamic and is on the top of the
+ ;; stack, so we can just bind it like usual
+ (byte-compile-dynamic-variable-bind var)
+ t)
+ (t
+ ;; VAR is dynamic, but we have to get its
+ ;; value out of the middle of the stack
+ (let ((stack-pos (cdr (assq var init-lexenv))))
+ (byte-compile-stack-ref stack-pos)
+ (byte-compile-dynamic-variable-bind var)
+ ;; Now we have to store nil into its temporary
+ ;; stack position to avoid problems with GC
+ (byte-compile-push-constant nil)
+ (byte-compile-stack-set stack-pos))
+ nil)))
+
+(defun byte-compile-unbind (clauses init-lexenv
+ &optional preserve-body-value)
+ "Emit byte-codes to unbind the variables bound by CLAUSES.
+CLAUSES is a `let'-style variable binding list. INIT-LEXENV should be a
+lexical-environment alist describing the positions of the init value that
+have been pushed on the stack. If PRESERVE-BODY-VALUE is true,
+then an additional value on the top of the stack, above any lexical binding
+slots, is preserved, so it will be on the top of the stack after all
+binding slots have been popped."
+ ;; Unbind dynamic variables
+ (let ((num-dynamic-bindings 0))
+ (dolist (clause clauses)
+ (unless (assq (if (consp clause) (car clause) clause)
+ byte-compile-lexical-environment)
+ (setq num-dynamic-bindings (1+ num-dynamic-bindings))))
+ (unless (zerop num-dynamic-bindings)
+ (byte-compile-out 'byte-unbind num-dynamic-bindings)))
+ ;; Pop lexical variables off the stack, possibly preserving the
+ ;; return value of the body.
+ (when init-lexenv
+ ;; INIT-LEXENV contains all init values left on the stack
+ (byte-compile-discard (length init-lexenv) preserve-body-value)))
(defun byte-compile-let (form)
"Generate code for the `let' form FORM."
(let ((clauses (cadr form))
- (lforminfo (and lexical-binding (byte-compile-compute-lforminfo form)))
- (init-lexenv nil)
- ;; bind these to restrict the scope of any changes
- (byte-compile-current-heap-environment
- byte-compile-current-heap-environment)
- (byte-compile-current-num-closures byte-compile-current-num-closures))
- (when (and lforminfo (byte-compile-non-stack-bindings-p clauses lforminfo))
- ;; Some of the variables we're binding are lexical variables on
- ;; the stack, but not all. As much as we can, rearrange the list
- ;; so that non-stack lexical variables and dynamically bound
- ;; variables come last, which allows slightly more optimal
- ;; byte-code for binding them.
- (setq clauses (byte-compile-rearrange-let-clauses clauses lforminfo)))
- ;; If necessary, create a new heap environment to hold some of the
- ;; variables bound here.
- (when lforminfo
- (setq init-lexenv (byte-compile-maybe-push-heap-environment lforminfo)))
- ;; First compute the binding values in the old scope.
- (dolist (clause clauses)
- (setq init-lexenv
- (byte-compile-push-binding-init clause init-lexenv lforminfo)))
- ;; Now do the bindings, execute the body, and undo the bindings
+ (init-lexenv nil))
+ (when (eq (car form) 'let)
+ ;; First compute the binding values in the old scope.
+ (dolist (var clauses)
+ (push (byte-compile-push-binding-init var) init-lexenv)))
+ ;; New scope.
(let ((byte-compile-bound-variables byte-compile-bound-variables)
- (byte-compile-lexical-environment byte-compile-lexical-environment)
- (preserve-body-value (not for-effect)))
- (dolist (clause (reverse clauses))
- (let ((var (if (consp clause) (car clause) clause)))
- (cond ((null lforminfo)
- ;; If there are no lexical bindings, we can do things simply.
- (byte-compile-dynamic-variable-bind var))
- ((byte-compile-bind var init-lexenv lforminfo)
- (pop init-lexenv)))))
- ;; Emit the body
- (byte-compile-body-do-effect (cdr (cdr form)))
- ;; Unbind the variables
- (if lforminfo
- ;; Unbind both lexical and dynamic variables
- (byte-compile-unbind clauses init-lexenv lforminfo preserve-body-value)
- ;; Unbind dynamic variables
- (byte-compile-out 'byte-unbind (length clauses))))))
-
-(defun byte-compile-let* (form)
- "Generate code for the `let*' form FORM."
- (let ((clauses (cadr form))
- (lforminfo (and lexical-binding (byte-compile-compute-lforminfo form)))
- (init-lexenv nil)
- (preserve-body-value (not for-effect))
- ;; bind these to restrict the scope of any changes
- (byte-compile-bound-variables byte-compile-bound-variables)
- (byte-compile-lexical-environment byte-compile-lexical-environment)
- (byte-compile-current-heap-environment
- byte-compile-current-heap-environment)
- (byte-compile-current-num-closures byte-compile-current-num-closures))
- ;; If necessary, create a new heap environment to hold some of the
- ;; variables bound here.
- (when lforminfo
- (setq init-lexenv (byte-compile-maybe-push-heap-environment lforminfo)))
- ;; Bind the variables
- (dolist (clause clauses)
- (setq init-lexenv
- (byte-compile-push-binding-init clause init-lexenv lforminfo))
- (let ((var (if (consp clause) (car clause) clause)))
- (cond ((null lforminfo)
- ;; If there are no lexical bindings, we can do things simply.
- (byte-compile-dynamic-variable-bind var))
- ((byte-compile-bind var init-lexenv lforminfo)
- (pop init-lexenv)))))
- ;; Emit the body
- (byte-compile-body-do-effect (cdr (cdr form)))
- ;; Unbind the variables
- (if lforminfo
- ;; Unbind both lexical and dynamic variables
- (byte-compile-unbind clauses init-lexenv lforminfo preserve-body-value)
- ;; Unbind dynamic variables
- (byte-compile-out 'byte-unbind (length clauses)))))
+ (byte-compile-lexical-environment byte-compile-lexical-environment))
+ ;; Bind the variables.
+ ;; For `let', do it in reverse order, because it makes no
+ ;; semantic difference, but it is a lot more efficient since the
+ ;; values are now in reverse order on the stack.
+ (dolist (var (if (eq (car form) 'let) (reverse clauses) clauses))
+ (unless (eq (car form) 'let)
+ (push (byte-compile-push-binding-init var) init-lexenv))
+ (let ((var (if (consp var) (car var) var)))
+ (cond ((null lexical-binding)
+ ;; If there are no lexical bindings, we can do things simply.
+ (byte-compile-dynamic-variable-bind var))
+ ((byte-compile-bind var init-lexenv)
+ (pop init-lexenv)))))
+ ;; Emit the body.
+ (let ((init-stack-depth byte-compile-depth))
+ (byte-compile-body-do-effect (cdr (cdr form)))
+ ;; Unbind the variables.
+ (if lexical-binding
+ ;; Unbind both lexical and dynamic variables.
+ (progn
+ (assert (or (eq byte-compile-depth init-stack-depth)
+ (eq byte-compile-depth (1+ init-stack-depth))))
+ (byte-compile-unbind clauses init-lexenv (> byte-compile-depth
+ init-stack-depth)))
+ ;; Unbind dynamic variables.
+ (byte-compile-out 'byte-unbind (length clauses)))))))
\f
(byte-defop-compiler-1 save-excursion)
(byte-defop-compiler-1 save-current-buffer)
(byte-defop-compiler-1 save-restriction)
-(byte-defop-compiler-1 save-window-excursion)
-(byte-defop-compiler-1 with-output-to-temp-buffer)
(byte-defop-compiler-1 track-mouse)
(defun byte-compile-catch (form)
(byte-compile-form (car (cdr form)))
- (byte-compile-push-constant
- (byte-compile-top-level (cons 'progn (cdr (cdr form))) for-effect))
+ (pcase (cddr form)
+ (`(:fun-body ,f)
+ (byte-compile-form `(list 'funcall ,f)))
+ (body
+ (byte-compile-push-constant
+ (byte-compile-top-level (cons 'progn body) for-effect))))
(byte-compile-out 'byte-catch 0))
(defun byte-compile-unwind-protect (form)
- (byte-compile-push-constant
- (byte-compile-top-level-body (cdr (cdr form)) t))
+ (pcase (cddr form)
+ (`(:fun-body ,f)
+ (byte-compile-form `(list (list 'funcall ,f))))
+ (handlers
+ (byte-compile-push-constant
+ (byte-compile-top-level-body handlers t))))
(byte-compile-out 'byte-unwind-protect 0)
(byte-compile-form-do-effect (car (cdr form)))
(byte-compile-out 'byte-unbind 1))
(defun byte-compile-track-mouse (form)
(byte-compile-form
- `(funcall '(lambda nil
- (track-mouse ,@(byte-compile-top-level-body (cdr form)))))))
+ (pcase form
+ (`(,_ :fun-body ,f) `(eval (list 'track-mouse (list 'funcall ,f))))
+ (_ `(eval '(track-mouse ,@(byte-compile-top-level-body (cdr form))))))))
(defun byte-compile-condition-case (form)
(let* ((var (nth 1 form))
- (byte-compile-bound-variables
- (if var (cons var byte-compile-bound-variables)
+ (fun-bodies (eq var :fun-body))
+ (byte-compile-bound-variables
+ (if (and var (not fun-bodies))
+ (cons var byte-compile-bound-variables)
byte-compile-bound-variables)))
(byte-compile-set-symbol-position 'condition-case)
(unless (symbolp var)
(byte-compile-warn
"`%s' is not a variable-name or nil (in condition-case)" var))
+ (if fun-bodies (setq var (make-symbol "err")))
(byte-compile-push-constant var)
- (byte-compile-push-constant (byte-compile-top-level
- (nth 2 form) for-effect))
- (let ((clauses (cdr (cdr (cdr form))))
- compiled-clauses)
- (while clauses
- (let* ((clause (car clauses))
- (condition (car clause)))
- (cond ((not (or (symbolp condition)
- (and (listp condition)
- (let ((syms condition) (ok t))
- (while syms
- (if (not (symbolp (car syms)))
- (setq ok nil))
- (setq syms (cdr syms)))
- ok))))
- (byte-compile-warn
- "`%s' is not a condition name or list of such (in condition-case)"
- (prin1-to-string condition)))
-;; ((not (or (eq condition 't)
-;; (and (stringp (get condition 'error-message))
-;; (consp (get condition 'error-conditions)))))
-;; (byte-compile-warn
-;; "`%s' is not a known condition name (in condition-case)"
-;; condition))
- )
- (setq compiled-clauses
- (cons (cons condition
- (byte-compile-top-level-body
- (cdr clause) for-effect))
- compiled-clauses)))
- (setq clauses (cdr clauses)))
- (byte-compile-push-constant (nreverse compiled-clauses)))
+ (if fun-bodies
+ (byte-compile-form `(list 'funcall ,(nth 2 form)))
+ (byte-compile-push-constant
+ (byte-compile-top-level (nth 2 form) for-effect)))
+ (let ((compiled-clauses
+ (mapcar
+ (lambda (clause)
+ (let ((condition (car clause)))
+ (cond ((not (or (symbolp condition)
+ (and (listp condition)
+ (let ((ok t))
+ (dolist (sym condition)
+ (if (not (symbolp sym))
+ (setq ok nil)))
+ ok))))
+ (byte-compile-warn
+ "`%S' is not a condition name or list of such (in condition-case)"
+ condition))
+ ;; (not (or (eq condition 't)
+ ;; (and (stringp (get condition 'error-message))
+ ;; (consp (get condition
+ ;; 'error-conditions)))))
+ ;; (byte-compile-warn
+ ;; "`%s' is not a known condition name
+ ;; (in condition-case)"
+ ;; condition))
+ )
+ (if fun-bodies
+ `(list ',condition (list 'funcall ,(cadr clause) ',var))
+ (cons condition
+ (byte-compile-top-level-body
+ (cdr clause) for-effect)))))
+ (cdr (cdr (cdr form))))))
+ (if fun-bodies
+ (byte-compile-form `(list ,@compiled-clauses))
+ (byte-compile-push-constant compiled-clauses)))
(byte-compile-out 'byte-condition-case 0)))
(byte-compile-out 'byte-save-current-buffer 0)
(byte-compile-body-do-effect (cdr form))
(byte-compile-out 'byte-unbind 1))
-
-(defun byte-compile-save-window-excursion (form)
- (byte-compile-push-constant
- (byte-compile-top-level-body (cdr form) for-effect))
- (byte-compile-out 'byte-save-window-excursion 0))
-
-(defun byte-compile-with-output-to-temp-buffer (form)
- (byte-compile-form (car (cdr form)))
- (byte-compile-out 'byte-temp-output-buffer-setup 0)
- (byte-compile-body (cdr (cdr form)))
- (byte-compile-out 'byte-temp-output-buffer-show 0))
\f
;;; top-level forms elsewhere
(defun byte-compile-defmacro (form)
;; This is not used for file-level defmacros with doc strings.
- ;; FIXME handle decls, use defalias?
- (let ((decls (byte-compile-defmacro-declaration form))
- (code (byte-compile-lambda (cdr (cdr form)) t))
- (for-effect nil))
- (byte-compile-push-constant (nth 1 form))
- (if (not (byte-compile-closure-code-p code))
- ;; simple lambda
- (byte-compile-push-constant (cons 'macro code))
- (byte-compile-push-constant 'macro)
- (byte-compile-make-closure code)
- (byte-compile-out 'byte-cons))
- (byte-compile-out 'byte-fset)
- (byte-compile-discard))
- (byte-compile-constant (nth 1 form)))
+ (byte-compile-body-do-effect
+ (let ((decls (byte-compile-defmacro-declaration form))
+ (code (byte-compile-byte-code-maker
+ (byte-compile-lambda (cdr (cdr form)) t))))
+ `((defalias ',(nth 1 form)
+ ,(if (eq (car-safe code) 'make-byte-code)
+ `(cons 'macro ,code)
+ `'(macro . ,(eval code))))
+ ,@decls
+ ',(nth 1 form)))))
(defun byte-compile-defvar (form)
;; This is not used for file-level defvar/consts with doc strings.
;; Lambdas in valid places are handled as special cases by various code.
;; The ones that remain are errors.
-(defun byte-compile-lambda-form (form)
+(defun byte-compile-lambda-form (_form)
(byte-compile-set-symbol-position 'lambda)
(error "`lambda' used as function name is invalid"))
(progn
;; ## remove this someday
(and byte-compile-depth
- (not (= (cdr (cdr tag)) byte-compile-depth))
- (error "Compiler bug: depth conflict at tag %d" (car (cdr tag))))
+ (not (= (cdr (cdr tag)) byte-compile-depth))
+ (error "Compiler bug: depth conflict at tag %d" (car (cdr tag))))
(setq byte-compile-depth (cdr (cdr tag))))
(setcdr (cdr tag) byte-compile-depth)))
(setq f (car f))
(if (string-match "elc\\'" f) (setq f (substring f 0 -1)))
(when (and (file-readable-p f)
- (file-newer-than-file-p f emacs-file))
+ (file-newer-than-file-p f emacs-file)
+ ;; Don't reload the source version of the files below
+ ;; because that causes subsequent byte-compilation to
+ ;; be a lot slower and need a higher max-lisp-eval-depth,
+ ;; so it can cause recompilation to fail.
+ (not (member (file-name-nondirectory f)
+ '("pcase.el" "bytecomp.el" "macroexp.el"
+ "cconv.el" "byte-opt.el"))))
(message "Reloading stale %s" (file-name-nondirectory f))
(condition-case nil
(load f 'noerror nil 'nosuffix)
(run-hooks 'bytecomp-load-hook)
-;; arch-tag: 9c97b0f0-8745-4571-bfc3-8dceb677292a
;;; bytecomp.el ends here