2011-03-10 09:52:33 -05:00
|
|
|
|
;;; byte-opt.el --- the optimization passes of the emacs-lisp byte compiler -*- lexical-binding: t -*-
|
1992-07-22 16:55:01 +00:00
|
|
|
|
|
2023-01-01 05:31:12 -05:00
|
|
|
|
;; Copyright (C) 1991, 1994, 2000-2023 Free Software Foundation, Inc.
|
1992-07-22 16:55:01 +00:00
|
|
|
|
|
|
|
|
|
;; Author: Jamie Zawinski <jwz@lucid.com>
|
|
|
|
|
;; Hallvard Furuseth <hbf@ulrik.uio.no>
|
2019-05-25 13:43:06 -07:00
|
|
|
|
;; Maintainer: emacs-devel@gnu.org
|
1992-07-22 16:55:01 +00:00
|
|
|
|
;; Keywords: internal
|
2010-08-29 12:17:13 -04:00
|
|
|
|
;; Package: emacs
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
|
|
2008-05-06 03:21:21 +00:00
|
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
1992-07-10 22:06:47 +00:00
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
2008-05-06 03:21:21 +00:00
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
;; (at your option) any later version.
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
2017-09-13 15:52:52 -07:00
|
|
|
|
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
1992-07-22 16:55:01 +00:00
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
1996-01-14 07:34:30 +00:00
|
|
|
|
;; ========================================================================
|
|
|
|
|
;; "No matter how hard you try, you can't make a racehorse out of a pig.
|
|
|
|
|
;; You can, however, make a faster pig."
|
|
|
|
|
;;
|
2022-02-17 16:35:03 +02:00
|
|
|
|
;; Or, to put it another way, the Emacs byte compiler is a VW Bug. This code
|
|
|
|
|
;; makes it be a VW Bug with fuel injection and a turbocharger... You're
|
|
|
|
|
;; still not going to make it go faster than 70 mph, but it might be easier
|
|
|
|
|
;; to get it there.
|
|
|
|
|
;;
|
1996-01-14 07:34:30 +00:00
|
|
|
|
;; TO DO:
|
|
|
|
|
;;
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; ;; An awful lot of functions always return a non-nil value. If they're
|
|
|
|
|
;; ;; error free also they may act as true-constants.
|
2022-01-02 16:11:45 +01:00
|
|
|
|
;;
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; (disassemble (lambda (x) (and (point) (foo))))
|
2022-01-02 16:11:45 +01:00
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; ;; When
|
|
|
|
|
;; ;; - all but one arguments to a function are constant
|
|
|
|
|
;; ;; - the non-constant argument is an if-expression (cond-expression?)
|
|
|
|
|
;; ;; then the outer function can be distributed. If the guarding
|
|
|
|
|
;; ;; condition is side-effect-free [assignment-free] then the other
|
|
|
|
|
;; ;; arguments may be any expressions. Since, however, the code size
|
|
|
|
|
;; ;; can increase this way they should be "simple". Compare:
|
2005-06-21 13:45:12 +00:00
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; (disassemble (lambda (x) (eq (if (point) 'a 'b) 'c)))
|
|
|
|
|
;; (disassemble (lambda (x) (if (point) (eq 'a 'c) (eq 'b 'c))))
|
2005-06-21 13:45:12 +00:00
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; ;; (car (cons A B)) -> (prog1 A B)
|
|
|
|
|
;; (disassemble (lambda (x) (car (cons (foo) 42))))
|
2005-06-21 13:45:12 +00:00
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; ;; (cdr (cons A B)) -> (progn A B)
|
|
|
|
|
;; (disassemble (lambda (x) (cdr (cons 42 (foo)))))
|
2005-06-21 13:45:12 +00:00
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; ;; (car (list A B ...)) -> (prog1 A B ...)
|
|
|
|
|
;; (disassemble (lambda (x) (car (list (foo) 42 (bar)))))
|
2005-06-21 13:45:12 +00:00
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; ;; (cdr (list A B ...)) -> (progn A (list B ...))
|
|
|
|
|
;; (disassemble (lambda (x) (cdr (list 42 (foo) (bar)))))
|
1995-07-17 22:44:06 +00:00
|
|
|
|
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
1992-07-22 16:55:01 +00:00
|
|
|
|
;;; Code:
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
1998-12-05 18:18:50 +00:00
|
|
|
|
(require 'bytecomp)
|
2012-06-10 09:28:26 -04:00
|
|
|
|
(eval-when-compile (require 'cl-lib))
|
2012-06-07 15:25:48 -04:00
|
|
|
|
(require 'macroexp)
|
2017-04-18 19:07:28 -04:00
|
|
|
|
(eval-when-compile (require 'subr-x))
|
1998-12-05 18:18:50 +00:00
|
|
|
|
|
2023-01-31 11:15:13 +01:00
|
|
|
|
(defun bytecomp--log-lap-arg (arg)
|
|
|
|
|
;; Convert an argument that may be a LAP operation to something printable.
|
|
|
|
|
(cond
|
|
|
|
|
;; Symbols are just stripped of their -byte prefix if any.
|
|
|
|
|
((symbolp arg)
|
|
|
|
|
(intern (string-remove-prefix "byte-" (symbol-name arg))))
|
|
|
|
|
;; Conses are assumed to be LAP ops or tags.
|
|
|
|
|
((and (consp arg) (symbolp (car arg)))
|
|
|
|
|
(let* ((head (car arg))
|
|
|
|
|
(tail (cdr arg))
|
|
|
|
|
(op (intern (string-remove-prefix "byte-" (symbol-name head)))))
|
|
|
|
|
(cond
|
|
|
|
|
((eq head 'TAG)
|
|
|
|
|
(format "%d:" (car tail)))
|
|
|
|
|
((memq head byte-goto-ops)
|
|
|
|
|
(format "(%s %d)" op (cadr tail)))
|
|
|
|
|
((memq head byte-constref-ops)
|
|
|
|
|
(format "(%s %s)"
|
|
|
|
|
(if (eq op 'constant) 'const op)
|
|
|
|
|
(if (numberp tail)
|
|
|
|
|
(format "<V%d>" tail) ; closure var reference
|
|
|
|
|
(format "%S" (car tail))))) ; actual constant
|
|
|
|
|
;; Ops with an immediate argument.
|
|
|
|
|
((memq op '( stack-ref stack-set call unbind
|
|
|
|
|
listN concatN insertN discardN discardN-preserve-tos))
|
|
|
|
|
(format "(%s %S)" op tail))
|
|
|
|
|
;; Without immediate, print just the symbol.
|
|
|
|
|
(t op))))
|
|
|
|
|
;; Anything else is printed as-is.
|
|
|
|
|
(t arg)))
|
|
|
|
|
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-compile-log-lap-1 (format &rest args)
|
|
|
|
|
(byte-compile-log-1
|
2023-01-31 11:15:13 +01:00
|
|
|
|
(apply #'format-message format (mapcar #'bytecomp--log-lap-arg args))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defmacro byte-compile-log-lap (format-string &rest args)
|
2004-04-16 12:51:06 +00:00
|
|
|
|
`(and (memq byte-optimize-log '(t byte))
|
|
|
|
|
(byte-compile-log-lap-1 ,format-string ,@args)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
|
2021-05-27 17:31:57 -04:00
|
|
|
|
(defvar byte-optimize--lexvars nil
|
|
|
|
|
"Lexical variables in scope, in reverse order of declaration.
|
|
|
|
|
Each element is on the form (NAME KEEP [VALUE]), where:
|
|
|
|
|
NAME is the variable name,
|
|
|
|
|
KEEP is a boolean indicating whether the binding must be retained,
|
|
|
|
|
VALUE, if present, is a substitutable expression.
|
|
|
|
|
Earlier variables shadow later ones with the same name.")
|
|
|
|
|
|
1992-07-10 22:06:47 +00:00
|
|
|
|
;;; byte-compile optimizers to support inlining
|
|
|
|
|
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'inline 'byte-optimizer #'byte-optimize-inline-handler)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-inline-handler (form)
|
|
|
|
|
"byte-optimize-handler for the `inline' special-form."
|
|
|
|
|
(cons 'progn
|
|
|
|
|
(mapcar
|
2000-06-12 05:06:37 +00:00
|
|
|
|
(lambda (sexp)
|
2004-11-14 06:19:52 +00:00
|
|
|
|
(let ((f (car-safe sexp)))
|
|
|
|
|
(if (and (symbolp f)
|
|
|
|
|
(or (cdr (assq f byte-compile-function-environment))
|
|
|
|
|
(not (or (not (fboundp f))
|
|
|
|
|
(cdr (assq f byte-compile-macro-environment))
|
|
|
|
|
(and (consp (setq f (symbol-function f)))
|
|
|
|
|
(eq (car f) 'macro))
|
|
|
|
|
(subrp f)))))
|
|
|
|
|
(byte-compile-inline-expand sexp)
|
|
|
|
|
sexp)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(cdr form))))
|
|
|
|
|
|
|
|
|
|
(defun byte-compile-inline-expand (form)
|
|
|
|
|
(let* ((name (car form))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(localfn (cdr (assq name byte-compile-function-environment)))
|
2014-01-06 18:34:05 -05:00
|
|
|
|
(fn (or localfn (symbol-function name))))
|
2012-07-25 21:27:33 -04:00
|
|
|
|
(when (autoloadp fn)
|
|
|
|
|
(autoload-do-load fn)
|
2014-01-06 18:34:05 -05:00
|
|
|
|
(setq fn (or (symbol-function name)
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(cdr (assq name byte-compile-function-environment)))))
|
|
|
|
|
(pcase fn
|
2018-11-05 01:22:15 +01:00
|
|
|
|
('nil
|
First commit of scratch/correct-warning-pos.
This branch is intended to generate correct position information in warning
and error messages from the byte compiler, and is intended thereby to fix bugs
It introduces a new mechanism, the symbol with position. This is taken over
from the previous git branch scratch/accurate-warning-pos which was abandoned
for being too slow. The main difference in the current branch is that the
symbol `nil' is never given a position, thus speeding up NILP markedly.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-optimize-form-code-walker, byte-optimize-let-form, byte-optimize-while)
(byte-optimize-apply): Use byte-compile-warn-x in place of byte-compile-warn.
* lisp/emacs-lisp/bytecomp.el (byte-compile--form-stack): New variable.
(byte-compile-strip-s-p-1, byte-compile-strip-symbol-positions): New
functions.
(byte-compile-recurse-toplevel, byte-compile-initial-macro-environment)
(byte-compile-preprocess, byte-compile-macroexpand-declare-function): Bind
print-symbols-bare to non-nil.
(byte-compile--first-symbol, byte-compile--warning-source-offset): New
functions.
(byte-compile-warning-prefix): Modify to output two sets of position
information, the old (incorrect) set and the new set.
(byte-compile-warn): Strip positions from symbols before outputting.
(byte-compile-warn-x): New function which outputs a correct position supplied
in an argument.
(byte-compile-warn-obsolete, byte-compile-emit-callargs-warn)
(byte-compile-format-warn, byte-compile-nogroup-warn)
(byte-compile-arglist-warn, byte-compile-docstring-length-warn)
(byte-compile-warn-about-unresolved-functions, byte-compile-file)
(byte-compile--check-prefixed-var, byte-compile--declare-var)
(byte-compile-file-form-defvar-function, byte-compile-file-form-defmumble)
(byte-compile-check-lambda-list, byte-compile--warn-lexical-dynamic)
(byte-compile-lambda, byte-compile-form, byte-compile-normal-call)
(byte-compile-check-variable, byte-compile-free-vars-warn)
(byte-compile-subr-wrong-args, byte-compile-fset, byte-compile-set-default)
(byte-compile-condition-case, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-make-variable-buffer-local, byte-compile-define-symbol-prop)
(byte-compile-define-keymap): Replace byte-compile-warn with
byte-compile-warn-x.
(byte-compile-file, compile-defun): Bind symbols-with-pos-enabled to non-nil.
(compile-defun, byte-compile-from-buffer): Use `read-positioning-symbols'
rather than plain `read'.
(byte-compile-toplevel-file-form, byte-compile-form): Dynamically bind
byte-compile--form-stack.
(byte-compile-file-form-autoload, byte-compile-file-form-defvar)
(byte-compile-file-form-make-obsolete, byte-compile-lambda)
(byte-compile-push-constant, byte-compile-cond-jump-table)
(byte-compile-define-keymap, byte-compile-annotate-call-tree):
Strip positions from symbols where they are unwanted.
(byte-compile-file-form-defvar): Strip positions from symbols using
`bare-symbol'.
(byte-compile-file-form-defmumble): New variable bare-name, a version of name
without its position.
(byte-compile-lambda): Similarly, new variable bare-arglist.
(byte-compile-free-vars-warn): New argument arg supplying position information
to byte-compile-warn-x.
(byte-compile-push-constant): Manipulation of symbol positions.
(display-call-tree): Strip positions from symbols.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use)
(cconv--analyze-function, cconv-analyze-form): Replace use of
byte-compile-warn with byte-compile-warn-x.
* lisp/emacs-lisp/cl-generic.el (cl-defmethod): New variable org-name which
will supply position information to a new macroexp-warn-and-return.
* lisp/emacs-lisp/cl-macs.el (cl-macs--strip-s-p-1)
(cl-macs--strip-symbol-positions): New functions to strip positions from
symbols in an expression. These duplicaate similarly named functions in
bytecomp.el.
* lisp/emacs-lisp/macroexpand.el (macroexp--warn-wrap): Calls
byte-compile-warn-x in place of byte-compile-warn.
(macroexp-warn-and-return): Commented out new position parameter _arg.
* src/.gdbinit: Add in code to handle symbols with position.
* src/alloc.c (XPNTR, set_symbol_name, valid_lisp_object_p, purecopy)
(mark_char_table, mark_object, survives_gc_p, symbol_uses_obj): Use
BARE_SYMBOL_P and XBARE_SYMBOL in place of the former SYMBOLP and XSYMBOL.
(build_symbol_with_pos): New function.
(Fgarbage_collect): Bind Qsymbols_with_pos_enabled to nil around the call to
garbage_collect.
* src/data.c (Ftype_of): Add case for PVEC_SYMBOL_WITH_POS.
(Fbare_symbol_p, Fsymbol_with_pos_p, Fbare_symbol, Fsymbol_with_pos_pos)
(Fposition_symbol): New functions.
(symbols_with_pos_enabled): New boolean variable.
* src/fns.c (internal_equal, hash_lookup): Handle symbols with position.
* src/keyboard.c (recursive_edit_1): Bind Qsymbols_with_pos_enabled and
Qprint_symbols_bare to nil.
* src/lisp.h (lisp_h_PSEUDOVECTORP): New macro.
(lisp_h_BASE_EQ): New name for the former lisp_h_EQ.
(lisp_h_EQ): Extended to handle symbols with position.
(lisp_h_NILP): Now uses BASE_EQ rather than EQ.
(lisp_h_SYMBOL_WITH_POS_P, lisp_h_BARE_SYMBOL_P): New macros.
(lisp_h_SYMBOLP): Redefined to handle symbols with position.
(BARE_SYMBOL_P, BASE_EQ): New macros.
(SYMBOLP (macro)): Removed.
(SYMBOLP (function), XSYMBOL, make_lisp_symbol, builtin_lisp_symbol)
(c_symbol_p): Moved to later in file.
(struct Lisp_Symbol_With_Pos): New data type.
(pvec_type): PVEC_SYMBOL_WITH_POS: New type code.
(PSEUDOVECTORP): Redefined to use the lisp_h_PSEUDOVECTORP.
(BARE_SYMBOL_P, SYMBOL_WITH_POS_P, SYMBOLP, XSYMBOL_WITH_POS, XBARE_SYMBOL)
(XSYMBOL, make_lisp_symbol, builtin_lisp_symbol, c_symbol_p, CHECK_SYMBOL)
(BASE_EQ): New functions, or functions moved from earlier in the file.
(SYMBOL_WITH_POS_SYM, SYMBOL_WITH_POS_POS): New INLINE functions.
* src/lread.c (read0, read1, read_list, read_vector, read_internal_start)
(list2): Add a new bool parameter locate_syms.
(Fread_positioning_symbols): New function.
(Fread_from_string, read_internal_start, read0, read1, read_list): Pass around
suitable values for locate_syms.
(read1): Build symbols with position when locate_syms is true.
* src/print.c (print_vectorlike): Add handling for PVEC_SYMBOL_WITH_POS.
(print_object): Replace EQ with BASE_EQ.
(print_symbols_bare): New boolean variable.
2021-11-29 11:19:31 +00:00
|
|
|
|
(byte-compile-warn-x name
|
|
|
|
|
"attempt to inline `%s' before it was defined"
|
|
|
|
|
name)
|
2011-03-16 16:08:39 -04:00
|
|
|
|
form)
|
|
|
|
|
(`(autoload . ,_)
|
Go back to grave quoting in source-code docstrings etc.
This reverts almost all my recent changes to use curved quotes
in docstrings and/or strings used for error diagnostics.
There are a few exceptions, e.g., Bahá’í proper names.
* admin/unidata/unidata-gen.el (unidata-gen-table):
* lisp/abbrev.el (expand-region-abbrevs):
* lisp/align.el (align-region):
* lisp/allout.el (allout-mode, allout-solicit-alternate-bullet)
(outlineify-sticky):
* lisp/apropos.el (apropos-library):
* lisp/bookmark.el (bookmark-default-annotation-text):
* lisp/button.el (button-category-symbol, button-put)
(make-text-button):
* lisp/calc/calc-aent.el (math-read-if, math-read-factor):
* lisp/calc/calc-embed.el (calc-do-embedded):
* lisp/calc/calc-ext.el (calc-user-function-list):
* lisp/calc/calc-graph.el (calc-graph-show-dumb):
* lisp/calc/calc-help.el (calc-describe-key)
(calc-describe-thing, calc-full-help):
* lisp/calc/calc-lang.el (calc-c-language)
(math-parse-fortran-vector-end, math-parse-tex-sum)
(math-parse-eqn-matrix, math-parse-eqn-prime)
(calc-yacas-language, calc-maxima-language, calc-giac-language)
(math-read-giac-subscr, math-read-math-subscr)
(math-read-big-rec, math-read-big-balance):
* lisp/calc/calc-misc.el (calc-help, report-calc-bug):
* lisp/calc/calc-mode.el (calc-auto-why, calc-save-modes)
(calc-auto-recompute):
* lisp/calc/calc-prog.el (calc-fix-token-name)
(calc-read-parse-table-part, calc-user-define-invocation)
(math-do-arg-check):
* lisp/calc/calc-store.el (calc-edit-variable):
* lisp/calc/calc-units.el (math-build-units-table-buffer):
* lisp/calc/calc-vec.el (math-read-brackets):
* lisp/calc/calc-yank.el (calc-edit-mode):
* lisp/calc/calc.el (calc, calc-do, calc-user-invocation):
* lisp/calendar/appt.el (appt-display-message):
* lisp/calendar/diary-lib.el (diary-check-diary-file)
(diary-mail-entries, diary-from-outlook):
* lisp/calendar/icalendar.el (icalendar-export-region)
(icalendar--convert-float-to-ical)
(icalendar--convert-date-to-ical)
(icalendar--convert-ical-to-diary)
(icalendar--convert-recurring-to-diary)
(icalendar--add-diary-entry):
* lisp/calendar/time-date.el (format-seconds):
* lisp/calendar/timeclock.el (timeclock-mode-line-display)
(timeclock-make-hours-explicit, timeclock-log-data):
* lisp/calendar/todo-mode.el (todo-prefix, todo-delete-category)
(todo-item-mark, todo-check-format)
(todo-insert-item--next-param, todo-edit-item--next-key)
(todo-mode):
* lisp/cedet/ede/pmake.el (ede-proj-makefile-insert-dist-rules):
* lisp/cedet/mode-local.el (describe-mode-local-overload)
(mode-local-print-binding, mode-local-describe-bindings-2):
* lisp/cedet/semantic/complete.el (semantic-displayor-show-request):
* lisp/cedet/srecode/srt-mode.el (srecode-macro-help):
* lisp/cus-start.el (standard):
* lisp/cus-theme.el (describe-theme-1):
* lisp/custom.el (custom-add-dependencies, custom-check-theme)
(custom--sort-vars-1, load-theme):
* lisp/descr-text.el (describe-text-properties-1, describe-char):
* lisp/dired-x.el (dired-do-run-mail):
* lisp/dired.el (dired-log):
* lisp/emacs-lisp/advice.el (ad-read-advised-function)
(ad-read-advice-class, ad-read-advice-name, ad-enable-advice)
(ad-disable-advice, ad-remove-advice, ad-set-argument)
(ad-set-arguments, ad--defalias-fset, ad-activate)
(ad-deactivate):
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-compile-unfold-lambda, byte-optimize-form-code-walker)
(byte-optimize-while, byte-optimize-apply):
* lisp/emacs-lisp/byte-run.el (defun, defsubst):
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode)
(byte-compile-log-file, byte-compile-format-warn)
(byte-compile-nogroup-warn, byte-compile-arglist-warn)
(byte-compile-cl-warn)
(byte-compile-warn-about-unresolved-functions)
(byte-compile-file, byte-compile--declare-var)
(byte-compile-file-form-defmumble, byte-compile-form)
(byte-compile-normal-call, byte-compile-check-variable)
(byte-compile-variable-ref, byte-compile-variable-set)
(byte-compile-subr-wrong-args, byte-compile-setq-default)
(byte-compile-negation-optimizer)
(byte-compile-condition-case--old)
(byte-compile-condition-case--new, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-lambda-form)
(byte-compile-make-variable-buffer-local, display-call-tree)
(batch-byte-compile):
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use):
* lisp/emacs-lisp/chart.el (chart-space-usage):
* lisp/emacs-lisp/check-declare.el (check-declare-scan)
(check-declare-warn, check-declare-file)
(check-declare-directory):
* lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine)
(checkdoc-message-text-engine):
* lisp/emacs-lisp/cl-extra.el (cl-parse-integer)
(cl--describe-class):
* lisp/emacs-lisp/cl-generic.el (cl-defgeneric)
(cl--generic-describe, cl-generic-generalizers):
* lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause, cl-tagbody)
(cl-symbol-macrolet):
* lisp/emacs-lisp/cl.el (cl-unload-function, flet):
* lisp/emacs-lisp/copyright.el (copyright)
(copyright-update-directory):
* lisp/emacs-lisp/edebug.el (edebug-read-list):
* lisp/emacs-lisp/eieio-base.el (eieio-persistent-read):
* lisp/emacs-lisp/eieio-core.el (eieio--slot-override)
(eieio-oref):
* lisp/emacs-lisp/eieio-opt.el (eieio-help-constructor):
* lisp/emacs-lisp/eieio-speedbar.el:
(eieio-speedbar-child-make-tag-lines)
(eieio-speedbar-child-description):
* lisp/emacs-lisp/eieio.el (defclass, change-class):
* lisp/emacs-lisp/elint.el (elint-file, elint-get-top-forms)
(elint-init-form, elint-check-defalias-form)
(elint-check-let-form):
* lisp/emacs-lisp/ert.el (ert-get-test, ert-results-mode-menu)
(ert-results-pop-to-backtrace-for-test-at-point)
(ert-results-pop-to-messages-for-test-at-point)
(ert-results-pop-to-should-forms-for-test-at-point)
(ert-describe-test):
* lisp/emacs-lisp/find-func.el (find-function-search-for-symbol)
(find-function-library):
* lisp/emacs-lisp/generator.el (iter-yield):
* lisp/emacs-lisp/gv.el (gv-define-simple-setter):
* lisp/emacs-lisp/lisp-mnt.el (lm-verify):
* lisp/emacs-lisp/macroexp.el (macroexp--obsolete-warning):
* lisp/emacs-lisp/map-ynp.el (map-y-or-n-p):
* lisp/emacs-lisp/nadvice.el (advice--make-docstring)
(advice--make, define-advice):
* lisp/emacs-lisp/package-x.el (package-upload-file):
* lisp/emacs-lisp/package.el (package-version-join)
(package-disabled-p, package-activate-1, package-activate)
(package--download-one-archive)
(package--download-and-read-archives)
(package-compute-transaction, package-install-from-archive)
(package-install, package-install-selected-packages)
(package-delete, package-autoremove, describe-package-1)
(package-install-button-action, package-delete-button-action)
(package-menu-hide-package, package-menu--list-to-prompt)
(package-menu--perform-transaction)
(package-menu--find-and-notify-upgrades):
* lisp/emacs-lisp/pcase.el (pcase-exhaustive, pcase--u1):
* lisp/emacs-lisp/re-builder.el (reb-enter-subexp-mode):
* lisp/emacs-lisp/ring.el (ring-previous, ring-next):
* lisp/emacs-lisp/rx.el (rx-check, rx-anything)
(rx-check-any-string, rx-check-any, rx-check-not, rx-=)
(rx-repeat, rx-check-backref, rx-syntax, rx-check-category)
(rx-form):
* lisp/emacs-lisp/smie.el (smie-config-save):
* lisp/emacs-lisp/subr-x.el (internal--check-binding):
* lisp/emacs-lisp/tabulated-list.el (tabulated-list-put-tag):
* lisp/emacs-lisp/testcover.el (testcover-1value):
* lisp/emacs-lisp/timer.el (timer-event-handler):
* lisp/emulation/viper-cmd.el (viper-toggle-parse-sexp-ignore-comments)
(viper-toggle-search-style, viper-kill-buffer)
(viper-brac-function):
* lisp/emulation/viper-macs.el (viper-record-kbd-macro):
* lisp/env.el (setenv):
* lisp/erc/erc-button.el (erc-nick-popup):
* lisp/erc/erc.el (erc-cmd-LOAD, erc-handle-login, english):
* lisp/eshell/em-dirs.el (eshell/cd):
* lisp/eshell/em-glob.el (eshell-glob-regexp)
(eshell-glob-entries):
* lisp/eshell/em-pred.el (eshell-parse-modifiers):
* lisp/eshell/esh-opt.el (eshell-show-usage):
* lisp/facemenu.el (facemenu-add-new-face)
(facemenu-add-new-color):
* lisp/faces.el (read-face-name, read-face-font, describe-face)
(x-resolve-font-name):
* lisp/files-x.el (modify-file-local-variable):
* lisp/files.el (locate-user-emacs-file, find-alternate-file)
(set-auto-mode, hack-one-local-variable--obsolete)
(dir-locals-set-directory-class, write-file, basic-save-buffer)
(delete-directory, copy-directory, recover-session)
(recover-session-finish, insert-directory)
(file-modes-char-to-who, file-modes-symbolic-to-number)
(move-file-to-trash):
* lisp/filesets.el (filesets-add-buffer, filesets-remove-buffer):
* lisp/find-cmd.el (find-generic, find-to-string):
* lisp/finder.el (finder-commentary):
* lisp/font-lock.el (font-lock-fontify-buffer):
* lisp/format.el (format-write-file, format-find-file)
(format-insert-file):
* lisp/frame.el (get-device-terminal, select-frame-by-name):
* lisp/fringe.el (fringe--check-style):
* lisp/gnus/nnmairix.el (nnmairix-widget-create-query):
* lisp/help-fns.el (help-fns--key-bindings)
(help-fns--compiler-macro, help-fns--parent-mode)
(help-fns--obsolete, help-fns--interactive-only)
(describe-function-1, describe-variable):
* lisp/help.el (describe-mode)
(describe-minor-mode-from-indicator):
* lisp/image.el (image-type):
* lisp/international/ccl.el (ccl-dump):
* lisp/international/fontset.el (x-must-resolve-font-name):
* lisp/international/mule-cmds.el (prefer-coding-system)
(select-safe-coding-system-interactively)
(select-safe-coding-system, activate-input-method)
(toggle-input-method, describe-current-input-method)
(describe-language-environment):
* lisp/international/mule-conf.el (code-offset):
* lisp/international/mule-diag.el (describe-character-set)
(list-input-methods-1):
* lisp/mail/feedmail.el (feedmail-run-the-queue):
* lisp/mouse.el (minor-mode-menu-from-indicator):
* lisp/mpc.el (mpc-playlist-rename):
* lisp/msb.el (msb--choose-menu):
* lisp/net/ange-ftp.el (ange-ftp-shell-command):
* lisp/net/imap.el (imap-interactive-login):
* lisp/net/mairix.el (mairix-widget-create-query):
* lisp/net/newst-backend.el (newsticker--sentinel-work):
* lisp/net/newst-treeview.el (newsticker--treeview-load):
* lisp/net/rlogin.el (rlogin):
* lisp/obsolete/iswitchb.el (iswitchb-possible-new-buffer):
* lisp/obsolete/otodo-mode.el (todo-more-important-p):
* lisp/obsolete/pgg-gpg.el (pgg-gpg-process-region):
* lisp/obsolete/pgg-pgp.el (pgg-pgp-process-region):
* lisp/obsolete/pgg-pgp5.el (pgg-pgp5-process-region):
* lisp/org/ob-core.el (org-babel-goto-named-src-block)
(org-babel-goto-named-result):
* lisp/org/ob-fortran.el (org-babel-fortran-ensure-main-wrap):
* lisp/org/ob-ref.el (org-babel-ref-resolve):
* lisp/org/org-agenda.el (org-agenda-prepare):
* lisp/org/org-clock.el (org-clock-notify-once-if-expired)
(org-clock-resolve):
* lisp/org/org-ctags.el (org-ctags-ask-rebuild-tags-file-then-find-tag):
* lisp/org/org-feed.el (org-feed-parse-atom-entry):
* lisp/org/org-habit.el (org-habit-parse-todo):
* lisp/org/org-mouse.el (org-mouse-popup-global-menu)
(org-mouse-context-menu):
* lisp/org/org-table.el (org-table-edit-formulas):
* lisp/org/ox.el (org-export-async-start):
* lisp/proced.el (proced-log):
* lisp/progmodes/ada-mode.el (ada-get-indent-case)
(ada-check-matching-start, ada-goto-matching-start):
* lisp/progmodes/ada-prj.el (ada-prj-display-page):
* lisp/progmodes/ada-xref.el (ada-find-executable):
* lisp/progmodes/ebrowse.el (ebrowse-tags-apropos):
* lisp/progmodes/etags.el (etags-tags-apropos-additional):
* lisp/progmodes/flymake.el (flymake-parse-err-lines)
(flymake-start-syntax-check-process):
* lisp/progmodes/python.el (python-shell-get-process-or-error)
(python-define-auxiliary-skeleton):
* lisp/progmodes/sql.el (sql-comint):
* lisp/progmodes/verilog-mode.el (verilog-load-file-at-point):
* lisp/progmodes/vhdl-mode.el (vhdl-widget-directory-validate):
* lisp/recentf.el (recentf-open-files):
* lisp/replace.el (query-replace-read-from)
(occur-after-change-function, occur-1):
* lisp/scroll-bar.el (scroll-bar-columns):
* lisp/server.el (server-get-auth-key):
* lisp/simple.el (execute-extended-command)
(undo-outer-limit-truncate, list-processes--refresh)
(compose-mail, set-variable, choose-completion-string)
(define-alternatives):
* lisp/startup.el (site-run-file, tty-handle-args, command-line)
(command-line-1):
* lisp/subr.el (noreturn, define-error, add-to-list)
(read-char-choice, version-to-list):
* lisp/term/common-win.el (x-handle-xrm-switch)
(x-handle-name-switch, x-handle-args):
* lisp/term/x-win.el (x-handle-parent-id, x-handle-smid):
* lisp/textmodes/reftex-ref.el (reftex-label):
* lisp/textmodes/reftex-toc.el (reftex-toc-rename-label):
* lisp/textmodes/two-column.el (2C-split):
* lisp/tutorial.el (tutorial--describe-nonstandard-key)
(tutorial--find-changed-keys):
* lisp/type-break.el (type-break-noninteractive-query):
* lisp/wdired.el (wdired-do-renames, wdired-do-symlink-changes)
(wdired-do-perm-changes):
* lisp/whitespace.el (whitespace-report-region):
Prefer grave quoting in source-code strings used to generate help
and diagnostics.
* lisp/faces.el (face-documentation):
No need to convert quotes, since the result is a docstring.
* lisp/info.el (Info-virtual-index-find-node)
(Info-virtual-index, info-apropos):
Simplify by generating only curved quotes, since info files are
typically that ways nowadays anyway.
* lisp/international/mule-diag.el (list-input-methods):
Don’t assume text quoting style is curved.
* lisp/org/org-bibtex.el (org-bibtex-fields):
Revert my recent changes, going back to the old quoting style.
2015-09-07 08:41:44 -07:00
|
|
|
|
(error "File `%s' didn't define `%s'" (nth 1 fn) name))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
((and (pred symbolp) (guard (not (eq fn t)))) ;A function alias.
|
|
|
|
|
(byte-compile-inline-expand (cons fn (cdr form))))
|
2011-03-22 20:53:36 -04:00
|
|
|
|
((pred byte-code-function-p)
|
|
|
|
|
;; (message "Inlining byte-code for %S!" name)
|
|
|
|
|
;; The byte-code will be really inlined in byte-compile-unfold-bcf.
|
2021-07-22 15:00:17 +02:00
|
|
|
|
(byte-compile--check-arity-bytecode form fn)
|
2011-03-22 20:53:36 -04:00
|
|
|
|
`(,fn ,@(cdr form)))
|
2012-06-27 23:31:27 -04:00
|
|
|
|
((or `(lambda . ,_) `(closure . ,_))
|
2021-05-27 17:31:57 -04:00
|
|
|
|
;; While byte-compile-unfold-bcf can inline dynbind byte-code into
|
|
|
|
|
;; letbind byte-code (or any other combination for that matter), we
|
|
|
|
|
;; can only inline dynbind source into dynbind source or letbind
|
|
|
|
|
;; source into letbind source.
|
|
|
|
|
;; When the function comes from another file, we byte-compile
|
|
|
|
|
;; the inlined function first, and then inline its byte-code.
|
|
|
|
|
;; This also has the advantage that the final code does not
|
|
|
|
|
;; depend on the order of compilation of ELisp files, making
|
|
|
|
|
;; the build more reproducible.
|
|
|
|
|
(if (eq fn localfn)
|
|
|
|
|
;; From the same file => same mode.
|
2021-05-25 13:38:05 -04:00
|
|
|
|
(macroexp--unfold-lambda `(,fn ,@(cdr form)))
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; Since we are called from inside the optimizer, we need to make
|
2021-05-27 14:03:14 +02:00
|
|
|
|
;; sure not to propagate lexvar values.
|
2021-05-27 17:31:57 -04:00
|
|
|
|
(let ((byte-optimize--lexvars nil)
|
|
|
|
|
;; Silence all compilation warnings: the useful ones should
|
|
|
|
|
;; be displayed when the function's source file will be
|
|
|
|
|
;; compiled anyway, but more importantly we would otherwise
|
|
|
|
|
;; emit spurious warnings here because we don't have the full
|
2022-10-26 22:41:09 +02:00
|
|
|
|
;; context, such as `declare-function's placed earlier in the
|
2021-05-27 17:31:57 -04:00
|
|
|
|
;; source file's code or `with-suppressed-warnings' that
|
|
|
|
|
;; surrounded the `defsubst'.
|
|
|
|
|
(byte-compile-warnings nil))
|
2021-05-27 14:03:14 +02:00
|
|
|
|
(byte-compile name))
|
2021-07-22 15:00:17 +02:00
|
|
|
|
(let ((bc (symbol-function name)))
|
|
|
|
|
(byte-compile--check-arity-bytecode form bc)
|
|
|
|
|
`(,bc ,@(cdr form)))))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
|
2015-06-16 20:04:35 -04:00
|
|
|
|
(_ ;; Give up on inlining.
|
2011-03-16 16:08:39 -04:00
|
|
|
|
form))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
;;; implementing source-level optimizers
|
|
|
|
|
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(defvar byte-optimize--vars-outside-loop nil
|
|
|
|
|
"Alist of variables lexically bound outside the innermost `while' loop.
|
|
|
|
|
Variables here are sensitive to mutation inside the loop, since this can
|
|
|
|
|
occur an indeterminate number of times and thus have effect on code
|
|
|
|
|
sequentially preceding the mutation itself.
|
|
|
|
|
Same format as `byte-optimize--lexvars', with shared structure and contents.")
|
|
|
|
|
|
2021-09-22 11:03:30 +02:00
|
|
|
|
(defvar byte-optimize--inhibit-outside-loop-constprop nil
|
|
|
|
|
"If t, don't propagate values for variables declared outside the inner loop.
|
|
|
|
|
This indicates the loop discovery phase.")
|
|
|
|
|
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(defvar byte-optimize--dynamic-vars nil
|
2022-07-13 13:00:31 +02:00
|
|
|
|
"List of variables declared as dynamic during optimization.")
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
|
2021-07-30 13:44:07 +02:00
|
|
|
|
(defvar byte-optimize--aliased-vars nil
|
|
|
|
|
"List of variables which may be aliased by other lexical variables.
|
|
|
|
|
If an entry in `byte-optimize--lexvars' has another variable as its VALUE,
|
|
|
|
|
then that other variable must be in this list.
|
|
|
|
|
This variable thus carries no essential information but is maintained
|
|
|
|
|
for speeding up processing.")
|
|
|
|
|
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(defun byte-optimize--substitutable-p (expr)
|
|
|
|
|
"Whether EXPR is a constant that can be propagated."
|
|
|
|
|
;; Only consider numbers, symbols and strings to be values for substitution
|
|
|
|
|
;; purposes. Numbers and symbols are immutable, and mutating string
|
|
|
|
|
;; literals (or results from constant-evaluated string-returning functions)
|
|
|
|
|
;; can be considered undefined.
|
|
|
|
|
;; (What about other quoted values, like conses?)
|
|
|
|
|
(or (booleanp expr)
|
|
|
|
|
(numberp expr)
|
|
|
|
|
(stringp expr)
|
|
|
|
|
(and (consp expr)
|
2021-12-11 22:11:08 +01:00
|
|
|
|
(or (and (memq (car expr) '(quote function))
|
|
|
|
|
(symbolp (cadr expr)))
|
|
|
|
|
;; (internal-get-closed-var N) can be considered constant for
|
|
|
|
|
;; const-prop purposes.
|
|
|
|
|
(and (eq (car expr) 'internal-get-closed-var)
|
|
|
|
|
(integerp (cadr expr)))))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(keywordp expr)))
|
|
|
|
|
|
2021-02-09 12:10:07 -05:00
|
|
|
|
(defmacro byte-optimize--pcase (exp &rest cases)
|
|
|
|
|
;; When we do
|
|
|
|
|
;;
|
|
|
|
|
;; (pcase EXP
|
|
|
|
|
;; (`(if ,exp ,then ,else) (DO-TEST))
|
|
|
|
|
;; (`(plus ,e2 ,e2) (DO-ADD))
|
|
|
|
|
;; (`(times ,e2 ,e2) (DO-MULT))
|
|
|
|
|
;; ...)
|
|
|
|
|
;;
|
|
|
|
|
;; we usually don't want to fall back to the default case if
|
|
|
|
|
;; the value of EXP is of a form like `(if E1 E2)' or `(plus E1)'
|
|
|
|
|
;; or `(times E1 E2 E3)', instead we either want to signal an error
|
|
|
|
|
;; that EXP has an unexpected shape, or we want to carry on as if
|
|
|
|
|
;; it had the right shape (ignore the extra data and pretend the missing
|
|
|
|
|
;; data is nil) because it should simply never happen.
|
|
|
|
|
;;
|
|
|
|
|
;; The macro below implements the second option by rewriting patterns
|
|
|
|
|
;; like `(if ,exp ,then ,else)'
|
|
|
|
|
;; to `(if . (or `(,exp ,then ,else) pcase--dontcare))'.
|
|
|
|
|
;;
|
|
|
|
|
;; The resulting macroexpansion is also significantly cleaner/smaller/faster.
|
2021-05-25 13:38:05 -04:00
|
|
|
|
(declare (indent 1) (debug pcase))
|
2021-02-09 12:10:07 -05:00
|
|
|
|
`(pcase ,exp
|
|
|
|
|
. ,(mapcar (lambda (case)
|
|
|
|
|
`(,(pcase (car case)
|
|
|
|
|
((and `(,'\` (,_ . (,'\, ,_))) pat) pat)
|
|
|
|
|
(`(,'\` (,head . ,tail))
|
|
|
|
|
(list '\`
|
|
|
|
|
(cons head
|
|
|
|
|
(list '\, `(or ,(list '\` tail) pcase--dontcare)))))
|
|
|
|
|
(pat pat))
|
|
|
|
|
. ,(cdr case)))
|
|
|
|
|
cases)))
|
|
|
|
|
|
Try and fix w32 build; misc cleanup.
* lisp/subr.el (apply-partially): Move from subr.el; don't use lexical-let.
(eval-after-load): Obey lexical-binding.
* lisp/simple.el (apply-partially): Move to subr.el.
* lisp/makefile.w32-in: Match changes in Makefile.in.
(BIG_STACK_DEPTH, BIG_STACK_OPTS, BYTE_COMPILE_FLAGS): New vars.
(.el.elc, compile-CMD, compile-SH, compile-always-CMD)
(compile-always-SH, compile-calc-CMD, compile-calc-SH): Use them.
(COMPILE_FIRST): Add pcase, macroexp, and cconv.
* lisp/emacs-lisp/macroexp.el (macroexpand-all-1): Silence warning about
calling CL's `compiler-macroexpand'.
* lisp/emacs-lisp/bytecomp.el (byte-compile-preprocess): New function.
(byte-compile-initial-macro-environment)
(byte-compile-toplevel-file-form, byte-compile, byte-compile-sexp): Use it.
(byte-compile-eval, byte-compile-eval-before-compile): Obey lexical-binding.
(byte-compile--for-effect): Rename from `for-effect'.
(display-call-tree): Use case.
* lisp/emacs-lisp/byte-opt.el (for-effect): Don't declare as dynamic.
(byte-optimize-form-code-walker, byte-optimize-form):
Revert to old arg name.
* lisp/Makefile.in (BYTE_COMPILE_FLAGS): New var.
(compile-onefile, .el.elc, compile-calc, recompile): Use it.
2011-03-11 22:32:43 -05:00
|
|
|
|
(defun byte-optimize-form-code-walker (form for-effect)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
;;
|
|
|
|
|
;; For normal function calls, We can just mapcar the optimizer the cdr. But
|
|
|
|
|
;; we need to have special knowledge of the syntax of the special forms
|
|
|
|
|
;; like let and defun (that's why they're special forms :-). (Actually,
|
|
|
|
|
;; the important aspect is that they are subrs that don't evaluate all of
|
|
|
|
|
;; their args.)
|
|
|
|
|
;;
|
2021-01-16 10:51:09 -05:00
|
|
|
|
;; FIXME: There are a bunch of `byte-compile-warn' here which arguably
|
|
|
|
|
;; have no place in an optimizer: the corresponding tests should be
|
|
|
|
|
;; performed in `macroexpand-all', or in `cconv', or in `bytecomp'.
|
|
|
|
|
(let ((fn (car-safe form)))
|
2021-02-09 12:10:07 -05:00
|
|
|
|
(byte-optimize--pcase form
|
2021-01-16 10:51:09 -05:00
|
|
|
|
((pred (not consp))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(cond
|
|
|
|
|
((and for-effect
|
|
|
|
|
(or byte-compile-delete-errors
|
|
|
|
|
(not (symbolp form))
|
2021-07-28 17:31:44 +02:00
|
|
|
|
(eq form t)
|
|
|
|
|
(keywordp form)))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
nil)
|
|
|
|
|
((symbolp form)
|
|
|
|
|
(let ((lexvar (assq form byte-optimize--lexvars)))
|
2021-07-28 17:31:44 +02:00
|
|
|
|
(cond
|
|
|
|
|
((not lexvar) form)
|
|
|
|
|
(for-effect nil)
|
2021-09-22 11:03:30 +02:00
|
|
|
|
((and (cddr lexvar) ; substitution available
|
|
|
|
|
;; Perform substitution, except during the loop mutation
|
|
|
|
|
;; discovery phase if the variable was bound outside the
|
|
|
|
|
;; innermost loop.
|
|
|
|
|
(not (and byte-optimize--inhibit-outside-loop-constprop
|
|
|
|
|
(assq form byte-optimize--vars-outside-loop))))
|
|
|
|
|
(caddr lexvar))
|
2021-07-28 17:31:44 +02:00
|
|
|
|
(t form))))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(t form)))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
(`(quote . ,v)
|
2021-07-21 10:54:43 +02:00
|
|
|
|
(if (or (not v) (cdr v))
|
First commit of scratch/correct-warning-pos.
This branch is intended to generate correct position information in warning
and error messages from the byte compiler, and is intended thereby to fix bugs
It introduces a new mechanism, the symbol with position. This is taken over
from the previous git branch scratch/accurate-warning-pos which was abandoned
for being too slow. The main difference in the current branch is that the
symbol `nil' is never given a position, thus speeding up NILP markedly.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-optimize-form-code-walker, byte-optimize-let-form, byte-optimize-while)
(byte-optimize-apply): Use byte-compile-warn-x in place of byte-compile-warn.
* lisp/emacs-lisp/bytecomp.el (byte-compile--form-stack): New variable.
(byte-compile-strip-s-p-1, byte-compile-strip-symbol-positions): New
functions.
(byte-compile-recurse-toplevel, byte-compile-initial-macro-environment)
(byte-compile-preprocess, byte-compile-macroexpand-declare-function): Bind
print-symbols-bare to non-nil.
(byte-compile--first-symbol, byte-compile--warning-source-offset): New
functions.
(byte-compile-warning-prefix): Modify to output two sets of position
information, the old (incorrect) set and the new set.
(byte-compile-warn): Strip positions from symbols before outputting.
(byte-compile-warn-x): New function which outputs a correct position supplied
in an argument.
(byte-compile-warn-obsolete, byte-compile-emit-callargs-warn)
(byte-compile-format-warn, byte-compile-nogroup-warn)
(byte-compile-arglist-warn, byte-compile-docstring-length-warn)
(byte-compile-warn-about-unresolved-functions, byte-compile-file)
(byte-compile--check-prefixed-var, byte-compile--declare-var)
(byte-compile-file-form-defvar-function, byte-compile-file-form-defmumble)
(byte-compile-check-lambda-list, byte-compile--warn-lexical-dynamic)
(byte-compile-lambda, byte-compile-form, byte-compile-normal-call)
(byte-compile-check-variable, byte-compile-free-vars-warn)
(byte-compile-subr-wrong-args, byte-compile-fset, byte-compile-set-default)
(byte-compile-condition-case, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-make-variable-buffer-local, byte-compile-define-symbol-prop)
(byte-compile-define-keymap): Replace byte-compile-warn with
byte-compile-warn-x.
(byte-compile-file, compile-defun): Bind symbols-with-pos-enabled to non-nil.
(compile-defun, byte-compile-from-buffer): Use `read-positioning-symbols'
rather than plain `read'.
(byte-compile-toplevel-file-form, byte-compile-form): Dynamically bind
byte-compile--form-stack.
(byte-compile-file-form-autoload, byte-compile-file-form-defvar)
(byte-compile-file-form-make-obsolete, byte-compile-lambda)
(byte-compile-push-constant, byte-compile-cond-jump-table)
(byte-compile-define-keymap, byte-compile-annotate-call-tree):
Strip positions from symbols where they are unwanted.
(byte-compile-file-form-defvar): Strip positions from symbols using
`bare-symbol'.
(byte-compile-file-form-defmumble): New variable bare-name, a version of name
without its position.
(byte-compile-lambda): Similarly, new variable bare-arglist.
(byte-compile-free-vars-warn): New argument arg supplying position information
to byte-compile-warn-x.
(byte-compile-push-constant): Manipulation of symbol positions.
(display-call-tree): Strip positions from symbols.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use)
(cconv--analyze-function, cconv-analyze-form): Replace use of
byte-compile-warn with byte-compile-warn-x.
* lisp/emacs-lisp/cl-generic.el (cl-defmethod): New variable org-name which
will supply position information to a new macroexp-warn-and-return.
* lisp/emacs-lisp/cl-macs.el (cl-macs--strip-s-p-1)
(cl-macs--strip-symbol-positions): New functions to strip positions from
symbols in an expression. These duplicaate similarly named functions in
bytecomp.el.
* lisp/emacs-lisp/macroexpand.el (macroexp--warn-wrap): Calls
byte-compile-warn-x in place of byte-compile-warn.
(macroexp-warn-and-return): Commented out new position parameter _arg.
* src/.gdbinit: Add in code to handle symbols with position.
* src/alloc.c (XPNTR, set_symbol_name, valid_lisp_object_p, purecopy)
(mark_char_table, mark_object, survives_gc_p, symbol_uses_obj): Use
BARE_SYMBOL_P and XBARE_SYMBOL in place of the former SYMBOLP and XSYMBOL.
(build_symbol_with_pos): New function.
(Fgarbage_collect): Bind Qsymbols_with_pos_enabled to nil around the call to
garbage_collect.
* src/data.c (Ftype_of): Add case for PVEC_SYMBOL_WITH_POS.
(Fbare_symbol_p, Fsymbol_with_pos_p, Fbare_symbol, Fsymbol_with_pos_pos)
(Fposition_symbol): New functions.
(symbols_with_pos_enabled): New boolean variable.
* src/fns.c (internal_equal, hash_lookup): Handle symbols with position.
* src/keyboard.c (recursive_edit_1): Bind Qsymbols_with_pos_enabled and
Qprint_symbols_bare to nil.
* src/lisp.h (lisp_h_PSEUDOVECTORP): New macro.
(lisp_h_BASE_EQ): New name for the former lisp_h_EQ.
(lisp_h_EQ): Extended to handle symbols with position.
(lisp_h_NILP): Now uses BASE_EQ rather than EQ.
(lisp_h_SYMBOL_WITH_POS_P, lisp_h_BARE_SYMBOL_P): New macros.
(lisp_h_SYMBOLP): Redefined to handle symbols with position.
(BARE_SYMBOL_P, BASE_EQ): New macros.
(SYMBOLP (macro)): Removed.
(SYMBOLP (function), XSYMBOL, make_lisp_symbol, builtin_lisp_symbol)
(c_symbol_p): Moved to later in file.
(struct Lisp_Symbol_With_Pos): New data type.
(pvec_type): PVEC_SYMBOL_WITH_POS: New type code.
(PSEUDOVECTORP): Redefined to use the lisp_h_PSEUDOVECTORP.
(BARE_SYMBOL_P, SYMBOL_WITH_POS_P, SYMBOLP, XSYMBOL_WITH_POS, XBARE_SYMBOL)
(XSYMBOL, make_lisp_symbol, builtin_lisp_symbol, c_symbol_p, CHECK_SYMBOL)
(BASE_EQ): New functions, or functions moved from earlier in the file.
(SYMBOL_WITH_POS_SYM, SYMBOL_WITH_POS_POS): New INLINE functions.
* src/lread.c (read0, read1, read_list, read_vector, read_internal_start)
(list2): Add a new bool parameter locate_syms.
(Fread_positioning_symbols): New function.
(Fread_from_string, read_internal_start, read0, read1, read_list): Pass around
suitable values for locate_syms.
(read1): Build symbols with position when locate_syms is true.
* src/print.c (print_vectorlike): Add handling for PVEC_SYMBOL_WITH_POS.
(print_object): Replace EQ with BASE_EQ.
(print_symbols_bare): New boolean variable.
2021-11-29 11:19:31 +00:00
|
|
|
|
(byte-compile-warn-x form "malformed quote form: `%s'"
|
|
|
|
|
form))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
;; Map (quote nil) to nil to simplify optimizer logic.
|
|
|
|
|
;; Map quoted constants to nil if for-effect (just because).
|
|
|
|
|
(and (car v)
|
|
|
|
|
(not for-effect)
|
|
|
|
|
form))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(`(,(or 'let 'let*) . ,rest)
|
2021-02-09 12:10:07 -05:00
|
|
|
|
(cons fn (byte-optimize-let-form fn rest for-effect)))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
(`(cond . ,clauses)
|
2021-09-11 14:46:45 +02:00
|
|
|
|
;; FIXME: The condition in the first clause is always executed, and
|
|
|
|
|
;; clause bodies are mutually exclusive -- use this for improved
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; optimization (see comment about `if' below).
|
2021-09-11 14:46:45 +02:00
|
|
|
|
(cons fn
|
|
|
|
|
(mapcar (lambda (clause)
|
|
|
|
|
(if (consp clause)
|
|
|
|
|
(cons
|
|
|
|
|
(byte-optimize-form (car clause) nil)
|
|
|
|
|
(byte-optimize-body (cdr clause) for-effect))
|
First commit of scratch/correct-warning-pos.
This branch is intended to generate correct position information in warning
and error messages from the byte compiler, and is intended thereby to fix bugs
It introduces a new mechanism, the symbol with position. This is taken over
from the previous git branch scratch/accurate-warning-pos which was abandoned
for being too slow. The main difference in the current branch is that the
symbol `nil' is never given a position, thus speeding up NILP markedly.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-optimize-form-code-walker, byte-optimize-let-form, byte-optimize-while)
(byte-optimize-apply): Use byte-compile-warn-x in place of byte-compile-warn.
* lisp/emacs-lisp/bytecomp.el (byte-compile--form-stack): New variable.
(byte-compile-strip-s-p-1, byte-compile-strip-symbol-positions): New
functions.
(byte-compile-recurse-toplevel, byte-compile-initial-macro-environment)
(byte-compile-preprocess, byte-compile-macroexpand-declare-function): Bind
print-symbols-bare to non-nil.
(byte-compile--first-symbol, byte-compile--warning-source-offset): New
functions.
(byte-compile-warning-prefix): Modify to output two sets of position
information, the old (incorrect) set and the new set.
(byte-compile-warn): Strip positions from symbols before outputting.
(byte-compile-warn-x): New function which outputs a correct position supplied
in an argument.
(byte-compile-warn-obsolete, byte-compile-emit-callargs-warn)
(byte-compile-format-warn, byte-compile-nogroup-warn)
(byte-compile-arglist-warn, byte-compile-docstring-length-warn)
(byte-compile-warn-about-unresolved-functions, byte-compile-file)
(byte-compile--check-prefixed-var, byte-compile--declare-var)
(byte-compile-file-form-defvar-function, byte-compile-file-form-defmumble)
(byte-compile-check-lambda-list, byte-compile--warn-lexical-dynamic)
(byte-compile-lambda, byte-compile-form, byte-compile-normal-call)
(byte-compile-check-variable, byte-compile-free-vars-warn)
(byte-compile-subr-wrong-args, byte-compile-fset, byte-compile-set-default)
(byte-compile-condition-case, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-make-variable-buffer-local, byte-compile-define-symbol-prop)
(byte-compile-define-keymap): Replace byte-compile-warn with
byte-compile-warn-x.
(byte-compile-file, compile-defun): Bind symbols-with-pos-enabled to non-nil.
(compile-defun, byte-compile-from-buffer): Use `read-positioning-symbols'
rather than plain `read'.
(byte-compile-toplevel-file-form, byte-compile-form): Dynamically bind
byte-compile--form-stack.
(byte-compile-file-form-autoload, byte-compile-file-form-defvar)
(byte-compile-file-form-make-obsolete, byte-compile-lambda)
(byte-compile-push-constant, byte-compile-cond-jump-table)
(byte-compile-define-keymap, byte-compile-annotate-call-tree):
Strip positions from symbols where they are unwanted.
(byte-compile-file-form-defvar): Strip positions from symbols using
`bare-symbol'.
(byte-compile-file-form-defmumble): New variable bare-name, a version of name
without its position.
(byte-compile-lambda): Similarly, new variable bare-arglist.
(byte-compile-free-vars-warn): New argument arg supplying position information
to byte-compile-warn-x.
(byte-compile-push-constant): Manipulation of symbol positions.
(display-call-tree): Strip positions from symbols.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use)
(cconv--analyze-function, cconv-analyze-form): Replace use of
byte-compile-warn with byte-compile-warn-x.
* lisp/emacs-lisp/cl-generic.el (cl-defmethod): New variable org-name which
will supply position information to a new macroexp-warn-and-return.
* lisp/emacs-lisp/cl-macs.el (cl-macs--strip-s-p-1)
(cl-macs--strip-symbol-positions): New functions to strip positions from
symbols in an expression. These duplicaate similarly named functions in
bytecomp.el.
* lisp/emacs-lisp/macroexpand.el (macroexp--warn-wrap): Calls
byte-compile-warn-x in place of byte-compile-warn.
(macroexp-warn-and-return): Commented out new position parameter _arg.
* src/.gdbinit: Add in code to handle symbols with position.
* src/alloc.c (XPNTR, set_symbol_name, valid_lisp_object_p, purecopy)
(mark_char_table, mark_object, survives_gc_p, symbol_uses_obj): Use
BARE_SYMBOL_P and XBARE_SYMBOL in place of the former SYMBOLP and XSYMBOL.
(build_symbol_with_pos): New function.
(Fgarbage_collect): Bind Qsymbols_with_pos_enabled to nil around the call to
garbage_collect.
* src/data.c (Ftype_of): Add case for PVEC_SYMBOL_WITH_POS.
(Fbare_symbol_p, Fsymbol_with_pos_p, Fbare_symbol, Fsymbol_with_pos_pos)
(Fposition_symbol): New functions.
(symbols_with_pos_enabled): New boolean variable.
* src/fns.c (internal_equal, hash_lookup): Handle symbols with position.
* src/keyboard.c (recursive_edit_1): Bind Qsymbols_with_pos_enabled and
Qprint_symbols_bare to nil.
* src/lisp.h (lisp_h_PSEUDOVECTORP): New macro.
(lisp_h_BASE_EQ): New name for the former lisp_h_EQ.
(lisp_h_EQ): Extended to handle symbols with position.
(lisp_h_NILP): Now uses BASE_EQ rather than EQ.
(lisp_h_SYMBOL_WITH_POS_P, lisp_h_BARE_SYMBOL_P): New macros.
(lisp_h_SYMBOLP): Redefined to handle symbols with position.
(BARE_SYMBOL_P, BASE_EQ): New macros.
(SYMBOLP (macro)): Removed.
(SYMBOLP (function), XSYMBOL, make_lisp_symbol, builtin_lisp_symbol)
(c_symbol_p): Moved to later in file.
(struct Lisp_Symbol_With_Pos): New data type.
(pvec_type): PVEC_SYMBOL_WITH_POS: New type code.
(PSEUDOVECTORP): Redefined to use the lisp_h_PSEUDOVECTORP.
(BARE_SYMBOL_P, SYMBOL_WITH_POS_P, SYMBOLP, XSYMBOL_WITH_POS, XBARE_SYMBOL)
(XSYMBOL, make_lisp_symbol, builtin_lisp_symbol, c_symbol_p, CHECK_SYMBOL)
(BASE_EQ): New functions, or functions moved from earlier in the file.
(SYMBOL_WITH_POS_SYM, SYMBOL_WITH_POS_POS): New INLINE functions.
* src/lread.c (read0, read1, read_list, read_vector, read_internal_start)
(list2): Add a new bool parameter locate_syms.
(Fread_positioning_symbols): New function.
(Fread_from_string, read_internal_start, read0, read1, read_list): Pass around
suitable values for locate_syms.
(read1): Build symbols with position when locate_syms is true.
* src/print.c (print_vectorlike): Add handling for PVEC_SYMBOL_WITH_POS.
(print_object): Replace EQ with BASE_EQ.
(print_symbols_bare): New boolean variable.
2021-11-29 11:19:31 +00:00
|
|
|
|
(byte-compile-warn-x
|
|
|
|
|
clause "malformed cond form: `%s'"
|
|
|
|
|
clause)
|
2021-09-11 14:46:45 +02:00
|
|
|
|
clause))
|
|
|
|
|
clauses)))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
(`(progn . ,exps)
|
|
|
|
|
;; As an extra added bonus, this simplifies (progn <x>) --> <x>.
|
|
|
|
|
(if (cdr exps)
|
|
|
|
|
(macroexp-progn (byte-optimize-body exps for-effect))
|
|
|
|
|
(byte-optimize-form (car exps) for-effect)))
|
2021-02-09 12:10:07 -05:00
|
|
|
|
(`(prog1 ,exp . ,exps)
|
2021-07-29 10:07:26 +02:00
|
|
|
|
(let ((exp-opt (byte-optimize-form exp for-effect)))
|
|
|
|
|
(if exps
|
|
|
|
|
(let ((exps-opt (byte-optimize-body exps t)))
|
|
|
|
|
(if (macroexp-const-p exp-opt)
|
|
|
|
|
`(progn ,@exps-opt ,exp-opt)
|
Byte compiler: Prevent special forms' symbols being replaced by bare symbols
These are symbols with position from source code, which should not be replaced
by bare symbols in, e.g., optimization functions.
* lisp/Makefile.in: (BYTE_COMPILE_FLAGS, compile-first case): Set
max-specpdl-size to 5000 for the benefit of lisp/emacs-lisp/comp.el.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker)
(byte-optimize--rename-var, byte-optimize-if, byte-optimize-letX)
* lisp/emacs-lisp/bytecomp.el (byte-compile-recurse-toplevel)
(byte-compile-lambda)
* lisp/emacs-lisp/cconv.el (cconv-convert)
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Preserve, e.g., (car
form) in the byte compiler, when this form's car is a symbol with position of
a special form, rather than replacing the symbol with a bare symbol, e.g.
'cond.
2022-04-22 19:11:31 +00:00
|
|
|
|
`(,fn ,exp-opt ,@exps-opt)))
|
2021-07-29 10:07:26 +02:00
|
|
|
|
exp-opt)))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
|
|
|
|
|
(`(,(or `save-excursion `save-restriction `save-current-buffer) . ,exps)
|
|
|
|
|
;; Those subrs which have an implicit progn; it's not quite good
|
|
|
|
|
;; enough to treat these like normal function calls.
|
|
|
|
|
;; This can turn (save-excursion ...) into (save-excursion) which
|
|
|
|
|
;; will be optimized away in the lap-optimize pass.
|
|
|
|
|
(cons fn (byte-optimize-body exps for-effect)))
|
|
|
|
|
|
|
|
|
|
(`(if ,test ,then . ,else)
|
2021-02-11 17:34:17 +01:00
|
|
|
|
;; FIXME: We are conservative here: any variable changed in the
|
|
|
|
|
;; THEN branch will be barred from substitution in the ELSE
|
|
|
|
|
;; branch, despite the branches being mutually exclusive.
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(let* ((test-opt (byte-optimize-form test nil))
|
2021-02-11 17:34:17 +01:00
|
|
|
|
(const (macroexp-const-p test-opt))
|
|
|
|
|
;; Avoid traversing dead branches.
|
|
|
|
|
(then-opt (and test-opt (byte-optimize-form then for-effect)))
|
|
|
|
|
(else-opt (and (not (and test-opt const))
|
|
|
|
|
(byte-optimize-body else for-effect))))
|
Byte compiler: Prevent special forms' symbols being replaced by bare symbols
These are symbols with position from source code, which should not be replaced
by bare symbols in, e.g., optimization functions.
* lisp/Makefile.in: (BYTE_COMPILE_FLAGS, compile-first case): Set
max-specpdl-size to 5000 for the benefit of lisp/emacs-lisp/comp.el.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker)
(byte-optimize--rename-var, byte-optimize-if, byte-optimize-letX)
* lisp/emacs-lisp/bytecomp.el (byte-compile-recurse-toplevel)
(byte-compile-lambda)
* lisp/emacs-lisp/cconv.el (cconv-convert)
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Preserve, e.g., (car
form) in the byte compiler, when this form's car is a symbol with position of
a special form, rather than replacing the symbol with a bare symbol, e.g.
'cond.
2022-04-22 19:11:31 +00:00
|
|
|
|
`(,fn ,test-opt ,then-opt . ,else-opt)))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
|
2021-09-11 14:46:45 +02:00
|
|
|
|
(`(,(or 'and 'or) . ,exps)
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
;; FIXME: We have to traverse the expressions in left-to-right
|
2021-02-07 10:35:36 +01:00
|
|
|
|
;; order (because that is the order of evaluation and variable
|
|
|
|
|
;; mutations must be found prior to their use), but doing so we miss
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; some optimization opportunities:
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
;; consider (and A B) in a for-effect context, where B => nil.
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; Then A could be optimized in a for-effect context too.
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(let ((tail exps)
|
|
|
|
|
(args nil))
|
2021-09-11 14:46:45 +02:00
|
|
|
|
(while tail
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(push (byte-optimize-form
|
|
|
|
|
(car tail) (and for-effect (null (cdr tail))))
|
|
|
|
|
args)
|
2021-09-11 14:46:45 +02:00
|
|
|
|
(setq tail (cdr tail)))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(cons fn (nreverse args))))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
|
|
|
|
|
(`(while ,exp . ,exps)
|
2021-09-22 11:03:30 +02:00
|
|
|
|
;; FIXME: If the loop condition is statically nil after substitution
|
|
|
|
|
;; of surrounding variables then we can eliminate the whole loop,
|
|
|
|
|
;; even if those variables are mutated inside the loop.
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; We currently don't perform this important optimization.
|
2021-09-11 14:46:45 +02:00
|
|
|
|
(let* ((byte-optimize--vars-outside-loop byte-optimize--lexvars)
|
2021-09-22 11:03:30 +02:00
|
|
|
|
(condition-body
|
|
|
|
|
(if byte-optimize--inhibit-outside-loop-constprop
|
|
|
|
|
;; We are already inside the discovery phase of an outer
|
|
|
|
|
;; loop so there is no need for traversing this loop twice.
|
|
|
|
|
(cons exp exps)
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; Discovery phase: run optimization without substitution
|
2021-09-22 11:03:30 +02:00
|
|
|
|
;; of variables bound outside this loop.
|
|
|
|
|
(let ((byte-optimize--inhibit-outside-loop-constprop t))
|
|
|
|
|
(cons (byte-optimize-form exp nil)
|
|
|
|
|
(byte-optimize-body exps t)))))
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; Optimize again, this time with constprop enabled (unless
|
2021-09-22 11:03:30 +02:00
|
|
|
|
;; we are in discovery of an outer loop),
|
|
|
|
|
;; as mutated variables have been marked as non-substitutable.
|
|
|
|
|
(condition (byte-optimize-form (car condition-body) nil))
|
|
|
|
|
(body (byte-optimize-body (cdr condition-body) t)))
|
Byte compiler: Prevent special forms' symbols being replaced by bare symbols
These are symbols with position from source code, which should not be replaced
by bare symbols in, e.g., optimization functions.
* lisp/Makefile.in: (BYTE_COMPILE_FLAGS, compile-first case): Set
max-specpdl-size to 5000 for the benefit of lisp/emacs-lisp/comp.el.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker)
(byte-optimize--rename-var, byte-optimize-if, byte-optimize-letX)
* lisp/emacs-lisp/bytecomp.el (byte-compile-recurse-toplevel)
(byte-compile-lambda)
* lisp/emacs-lisp/cconv.el (cconv-convert)
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Preserve, e.g., (car
form) in the byte compiler, when this form's car is a symbol with position of
a special form, rather than replacing the symbol with a bare symbol, e.g.
'cond.
2022-04-22 19:11:31 +00:00
|
|
|
|
`(,fn ,condition . ,body)))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
|
2021-01-16 10:51:09 -05:00
|
|
|
|
(`(interactive . ,_)
|
First commit of scratch/correct-warning-pos.
This branch is intended to generate correct position information in warning
and error messages from the byte compiler, and is intended thereby to fix bugs
It introduces a new mechanism, the symbol with position. This is taken over
from the previous git branch scratch/accurate-warning-pos which was abandoned
for being too slow. The main difference in the current branch is that the
symbol `nil' is never given a position, thus speeding up NILP markedly.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-optimize-form-code-walker, byte-optimize-let-form, byte-optimize-while)
(byte-optimize-apply): Use byte-compile-warn-x in place of byte-compile-warn.
* lisp/emacs-lisp/bytecomp.el (byte-compile--form-stack): New variable.
(byte-compile-strip-s-p-1, byte-compile-strip-symbol-positions): New
functions.
(byte-compile-recurse-toplevel, byte-compile-initial-macro-environment)
(byte-compile-preprocess, byte-compile-macroexpand-declare-function): Bind
print-symbols-bare to non-nil.
(byte-compile--first-symbol, byte-compile--warning-source-offset): New
functions.
(byte-compile-warning-prefix): Modify to output two sets of position
information, the old (incorrect) set and the new set.
(byte-compile-warn): Strip positions from symbols before outputting.
(byte-compile-warn-x): New function which outputs a correct position supplied
in an argument.
(byte-compile-warn-obsolete, byte-compile-emit-callargs-warn)
(byte-compile-format-warn, byte-compile-nogroup-warn)
(byte-compile-arglist-warn, byte-compile-docstring-length-warn)
(byte-compile-warn-about-unresolved-functions, byte-compile-file)
(byte-compile--check-prefixed-var, byte-compile--declare-var)
(byte-compile-file-form-defvar-function, byte-compile-file-form-defmumble)
(byte-compile-check-lambda-list, byte-compile--warn-lexical-dynamic)
(byte-compile-lambda, byte-compile-form, byte-compile-normal-call)
(byte-compile-check-variable, byte-compile-free-vars-warn)
(byte-compile-subr-wrong-args, byte-compile-fset, byte-compile-set-default)
(byte-compile-condition-case, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-make-variable-buffer-local, byte-compile-define-symbol-prop)
(byte-compile-define-keymap): Replace byte-compile-warn with
byte-compile-warn-x.
(byte-compile-file, compile-defun): Bind symbols-with-pos-enabled to non-nil.
(compile-defun, byte-compile-from-buffer): Use `read-positioning-symbols'
rather than plain `read'.
(byte-compile-toplevel-file-form, byte-compile-form): Dynamically bind
byte-compile--form-stack.
(byte-compile-file-form-autoload, byte-compile-file-form-defvar)
(byte-compile-file-form-make-obsolete, byte-compile-lambda)
(byte-compile-push-constant, byte-compile-cond-jump-table)
(byte-compile-define-keymap, byte-compile-annotate-call-tree):
Strip positions from symbols where they are unwanted.
(byte-compile-file-form-defvar): Strip positions from symbols using
`bare-symbol'.
(byte-compile-file-form-defmumble): New variable bare-name, a version of name
without its position.
(byte-compile-lambda): Similarly, new variable bare-arglist.
(byte-compile-free-vars-warn): New argument arg supplying position information
to byte-compile-warn-x.
(byte-compile-push-constant): Manipulation of symbol positions.
(display-call-tree): Strip positions from symbols.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use)
(cconv--analyze-function, cconv-analyze-form): Replace use of
byte-compile-warn with byte-compile-warn-x.
* lisp/emacs-lisp/cl-generic.el (cl-defmethod): New variable org-name which
will supply position information to a new macroexp-warn-and-return.
* lisp/emacs-lisp/cl-macs.el (cl-macs--strip-s-p-1)
(cl-macs--strip-symbol-positions): New functions to strip positions from
symbols in an expression. These duplicaate similarly named functions in
bytecomp.el.
* lisp/emacs-lisp/macroexpand.el (macroexp--warn-wrap): Calls
byte-compile-warn-x in place of byte-compile-warn.
(macroexp-warn-and-return): Commented out new position parameter _arg.
* src/.gdbinit: Add in code to handle symbols with position.
* src/alloc.c (XPNTR, set_symbol_name, valid_lisp_object_p, purecopy)
(mark_char_table, mark_object, survives_gc_p, symbol_uses_obj): Use
BARE_SYMBOL_P and XBARE_SYMBOL in place of the former SYMBOLP and XSYMBOL.
(build_symbol_with_pos): New function.
(Fgarbage_collect): Bind Qsymbols_with_pos_enabled to nil around the call to
garbage_collect.
* src/data.c (Ftype_of): Add case for PVEC_SYMBOL_WITH_POS.
(Fbare_symbol_p, Fsymbol_with_pos_p, Fbare_symbol, Fsymbol_with_pos_pos)
(Fposition_symbol): New functions.
(symbols_with_pos_enabled): New boolean variable.
* src/fns.c (internal_equal, hash_lookup): Handle symbols with position.
* src/keyboard.c (recursive_edit_1): Bind Qsymbols_with_pos_enabled and
Qprint_symbols_bare to nil.
* src/lisp.h (lisp_h_PSEUDOVECTORP): New macro.
(lisp_h_BASE_EQ): New name for the former lisp_h_EQ.
(lisp_h_EQ): Extended to handle symbols with position.
(lisp_h_NILP): Now uses BASE_EQ rather than EQ.
(lisp_h_SYMBOL_WITH_POS_P, lisp_h_BARE_SYMBOL_P): New macros.
(lisp_h_SYMBOLP): Redefined to handle symbols with position.
(BARE_SYMBOL_P, BASE_EQ): New macros.
(SYMBOLP (macro)): Removed.
(SYMBOLP (function), XSYMBOL, make_lisp_symbol, builtin_lisp_symbol)
(c_symbol_p): Moved to later in file.
(struct Lisp_Symbol_With_Pos): New data type.
(pvec_type): PVEC_SYMBOL_WITH_POS: New type code.
(PSEUDOVECTORP): Redefined to use the lisp_h_PSEUDOVECTORP.
(BARE_SYMBOL_P, SYMBOL_WITH_POS_P, SYMBOLP, XSYMBOL_WITH_POS, XBARE_SYMBOL)
(XSYMBOL, make_lisp_symbol, builtin_lisp_symbol, c_symbol_p, CHECK_SYMBOL)
(BASE_EQ): New functions, or functions moved from earlier in the file.
(SYMBOL_WITH_POS_SYM, SYMBOL_WITH_POS_POS): New INLINE functions.
* src/lread.c (read0, read1, read_list, read_vector, read_internal_start)
(list2): Add a new bool parameter locate_syms.
(Fread_positioning_symbols): New function.
(Fread_from_string, read_internal_start, read0, read1, read_list): Pass around
suitable values for locate_syms.
(read1): Build symbols with position when locate_syms is true.
* src/print.c (print_vectorlike): Add handling for PVEC_SYMBOL_WITH_POS.
(print_object): Replace EQ with BASE_EQ.
(print_symbols_bare): New boolean variable.
2021-11-29 11:19:31 +00:00
|
|
|
|
(byte-compile-warn-x form "misplaced interactive spec: `%s'" form)
|
2021-01-16 10:51:09 -05:00
|
|
|
|
nil)
|
|
|
|
|
|
|
|
|
|
(`(function . ,_)
|
|
|
|
|
;; This forms is compiled as constant or by breaking out
|
|
|
|
|
;; all the subexpressions and compiling them separately.
|
2022-06-26 18:46:13 +02:00
|
|
|
|
(and (not for-effect) form))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
|
2021-02-09 12:10:07 -05:00
|
|
|
|
(`(condition-case ,var ,exp . ,clauses)
|
Byte compiler: Prevent special forms' symbols being replaced by bare symbols
These are symbols with position from source code, which should not be replaced
by bare symbols in, e.g., optimization functions.
* lisp/Makefile.in: (BYTE_COMPILE_FLAGS, compile-first case): Set
max-specpdl-size to 5000 for the benefit of lisp/emacs-lisp/comp.el.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker)
(byte-optimize--rename-var, byte-optimize-if, byte-optimize-letX)
* lisp/emacs-lisp/bytecomp.el (byte-compile-recurse-toplevel)
(byte-compile-lambda)
* lisp/emacs-lisp/cconv.el (cconv-convert)
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Preserve, e.g., (car
form) in the byte compiler, when this form's car is a symbol with position of
a special form, rather than replacing the symbol with a bare symbol, e.g.
'cond.
2022-04-22 19:11:31 +00:00
|
|
|
|
`(,fn ,var ;Not evaluated.
|
2022-12-23 20:04:22 +01:00
|
|
|
|
,(byte-optimize-form exp
|
|
|
|
|
(if (assq :success clauses)
|
|
|
|
|
(null var)
|
|
|
|
|
for-effect))
|
2021-09-11 14:46:45 +02:00
|
|
|
|
,@(mapcar (lambda (clause)
|
|
|
|
|
(let ((byte-optimize--lexvars
|
|
|
|
|
(and lexical-binding
|
|
|
|
|
(if var
|
|
|
|
|
(cons (list var t)
|
|
|
|
|
byte-optimize--lexvars)
|
|
|
|
|
byte-optimize--lexvars))))
|
|
|
|
|
(cons (car clause)
|
|
|
|
|
(byte-optimize-body (cdr clause) for-effect))))
|
|
|
|
|
clauses)))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
|
2022-06-26 18:46:13 +02:00
|
|
|
|
;; `unwind-protect' is a special form which here takes the shape
|
|
|
|
|
;; (unwind-protect EXPR :fun-body UNWIND-FUN).
|
|
|
|
|
;; We can treat it as if it were a plain function at this point,
|
2022-07-14 11:55:52 +02:00
|
|
|
|
;; although there are specific optimizations possible.
|
2022-06-26 18:46:13 +02:00
|
|
|
|
;; In particular, the return value of UNWIND-FUN is never used
|
|
|
|
|
;; so its body should really be compiled for-effect, but we
|
|
|
|
|
;; don't do that right now.
|
2021-01-16 10:51:09 -05:00
|
|
|
|
|
2021-02-09 12:10:07 -05:00
|
|
|
|
(`(catch ,tag . ,exps)
|
Byte compiler: Prevent special forms' symbols being replaced by bare symbols
These are symbols with position from source code, which should not be replaced
by bare symbols in, e.g., optimization functions.
* lisp/Makefile.in: (BYTE_COMPILE_FLAGS, compile-first case): Set
max-specpdl-size to 5000 for the benefit of lisp/emacs-lisp/comp.el.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker)
(byte-optimize--rename-var, byte-optimize-if, byte-optimize-letX)
* lisp/emacs-lisp/bytecomp.el (byte-compile-recurse-toplevel)
(byte-compile-lambda)
* lisp/emacs-lisp/cconv.el (cconv-convert)
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Preserve, e.g., (car
form) in the byte compiler, when this form's car is a symbol with position of
a special form, rather than replacing the symbol with a bare symbol, e.g.
'cond.
2022-04-22 19:11:31 +00:00
|
|
|
|
`(,fn ,(byte-optimize-form tag nil)
|
2021-09-11 14:46:45 +02:00
|
|
|
|
. ,(byte-optimize-body exps for-effect)))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
|
|
|
|
|
;; Needed as long as we run byte-optimize-form after cconv.
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(`(internal-make-closure . ,_)
|
2022-06-26 18:46:13 +02:00
|
|
|
|
(and (not for-effect)
|
|
|
|
|
(progn
|
2021-02-07 10:35:36 +01:00
|
|
|
|
;; Look up free vars and mark them to be kept, so that they
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; won't be optimized away.
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(dolist (var (caddr form))
|
|
|
|
|
(let ((lexvar (assq var byte-optimize--lexvars)))
|
|
|
|
|
(when lexvar
|
|
|
|
|
(setcar (cdr lexvar) t))))
|
2022-06-26 18:46:13 +02:00
|
|
|
|
form)))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
|
|
|
|
|
(`((lambda . ,_) . ,_)
|
2021-02-09 12:02:25 -05:00
|
|
|
|
(let ((newform (macroexp--unfold-lambda form)))
|
2021-01-16 10:51:09 -05:00
|
|
|
|
(if (eq newform form)
|
|
|
|
|
;; Some error occurred, avoid infinite recursion.
|
|
|
|
|
form
|
|
|
|
|
(byte-optimize-form newform for-effect))))
|
|
|
|
|
|
|
|
|
|
;; FIXME: Strictly speaking, I think this is a bug: (closure...)
|
|
|
|
|
;; is a *value* and shouldn't appear in the car.
|
|
|
|
|
(`((closure . ,_) . ,_) form)
|
|
|
|
|
|
2022-06-03 20:31:10 +02:00
|
|
|
|
(`(setq ,var ,expr)
|
|
|
|
|
(let ((lexvar (assq var byte-optimize--lexvars))
|
|
|
|
|
(value (byte-optimize-form expr nil)))
|
|
|
|
|
(when lexvar
|
|
|
|
|
(setcar (cdr lexvar) t) ; Mark variable to be kept.
|
|
|
|
|
(setcdr (cdr lexvar) nil) ; Inhibit further substitution.
|
|
|
|
|
|
|
|
|
|
(when (memq var byte-optimize--aliased-vars)
|
|
|
|
|
;; Cancel aliasing of variables aliased to this one.
|
|
|
|
|
(dolist (v byte-optimize--lexvars)
|
|
|
|
|
(when (eq (nth 2 v) var)
|
|
|
|
|
;; V is bound to VAR but VAR is now mutated:
|
|
|
|
|
;; cancel aliasing.
|
|
|
|
|
(setcdr (cdr v) nil)))))
|
|
|
|
|
`(,fn ,var ,value)))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
|
2021-03-04 21:06:13 +00:00
|
|
|
|
(`(defvar ,(and (pred symbolp) name) . ,rest)
|
|
|
|
|
(let ((optimized-rest (and rest
|
|
|
|
|
(cons (byte-optimize-form (car rest) nil)
|
|
|
|
|
(cdr rest)))))
|
|
|
|
|
(push name byte-optimize--dynamic-vars)
|
Byte compiler: Prevent special forms' symbols being replaced by bare symbols
These are symbols with position from source code, which should not be replaced
by bare symbols in, e.g., optimization functions.
* lisp/Makefile.in: (BYTE_COMPILE_FLAGS, compile-first case): Set
max-specpdl-size to 5000 for the benefit of lisp/emacs-lisp/comp.el.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker)
(byte-optimize--rename-var, byte-optimize-if, byte-optimize-letX)
* lisp/emacs-lisp/bytecomp.el (byte-compile-recurse-toplevel)
(byte-compile-lambda)
* lisp/emacs-lisp/cconv.el (cconv-convert)
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Preserve, e.g., (car
form) in the byte compiler, when this form's car is a symbol with position of
a special form, rather than replacing the symbol with a bare symbol, e.g.
'cond.
2022-04-22 19:11:31 +00:00
|
|
|
|
`(,fn ,name . ,optimized-rest)))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
|
2021-01-16 10:51:09 -05:00
|
|
|
|
(`(,(pred byte-code-function-p) . ,exps)
|
|
|
|
|
(cons fn (mapcar #'byte-optimize-form exps)))
|
|
|
|
|
|
|
|
|
|
(`(,(pred (not symbolp)) . ,_)
|
First commit of scratch/correct-warning-pos.
This branch is intended to generate correct position information in warning
and error messages from the byte compiler, and is intended thereby to fix bugs
It introduces a new mechanism, the symbol with position. This is taken over
from the previous git branch scratch/accurate-warning-pos which was abandoned
for being too slow. The main difference in the current branch is that the
symbol `nil' is never given a position, thus speeding up NILP markedly.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-optimize-form-code-walker, byte-optimize-let-form, byte-optimize-while)
(byte-optimize-apply): Use byte-compile-warn-x in place of byte-compile-warn.
* lisp/emacs-lisp/bytecomp.el (byte-compile--form-stack): New variable.
(byte-compile-strip-s-p-1, byte-compile-strip-symbol-positions): New
functions.
(byte-compile-recurse-toplevel, byte-compile-initial-macro-environment)
(byte-compile-preprocess, byte-compile-macroexpand-declare-function): Bind
print-symbols-bare to non-nil.
(byte-compile--first-symbol, byte-compile--warning-source-offset): New
functions.
(byte-compile-warning-prefix): Modify to output two sets of position
information, the old (incorrect) set and the new set.
(byte-compile-warn): Strip positions from symbols before outputting.
(byte-compile-warn-x): New function which outputs a correct position supplied
in an argument.
(byte-compile-warn-obsolete, byte-compile-emit-callargs-warn)
(byte-compile-format-warn, byte-compile-nogroup-warn)
(byte-compile-arglist-warn, byte-compile-docstring-length-warn)
(byte-compile-warn-about-unresolved-functions, byte-compile-file)
(byte-compile--check-prefixed-var, byte-compile--declare-var)
(byte-compile-file-form-defvar-function, byte-compile-file-form-defmumble)
(byte-compile-check-lambda-list, byte-compile--warn-lexical-dynamic)
(byte-compile-lambda, byte-compile-form, byte-compile-normal-call)
(byte-compile-check-variable, byte-compile-free-vars-warn)
(byte-compile-subr-wrong-args, byte-compile-fset, byte-compile-set-default)
(byte-compile-condition-case, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-make-variable-buffer-local, byte-compile-define-symbol-prop)
(byte-compile-define-keymap): Replace byte-compile-warn with
byte-compile-warn-x.
(byte-compile-file, compile-defun): Bind symbols-with-pos-enabled to non-nil.
(compile-defun, byte-compile-from-buffer): Use `read-positioning-symbols'
rather than plain `read'.
(byte-compile-toplevel-file-form, byte-compile-form): Dynamically bind
byte-compile--form-stack.
(byte-compile-file-form-autoload, byte-compile-file-form-defvar)
(byte-compile-file-form-make-obsolete, byte-compile-lambda)
(byte-compile-push-constant, byte-compile-cond-jump-table)
(byte-compile-define-keymap, byte-compile-annotate-call-tree):
Strip positions from symbols where they are unwanted.
(byte-compile-file-form-defvar): Strip positions from symbols using
`bare-symbol'.
(byte-compile-file-form-defmumble): New variable bare-name, a version of name
without its position.
(byte-compile-lambda): Similarly, new variable bare-arglist.
(byte-compile-free-vars-warn): New argument arg supplying position information
to byte-compile-warn-x.
(byte-compile-push-constant): Manipulation of symbol positions.
(display-call-tree): Strip positions from symbols.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use)
(cconv--analyze-function, cconv-analyze-form): Replace use of
byte-compile-warn with byte-compile-warn-x.
* lisp/emacs-lisp/cl-generic.el (cl-defmethod): New variable org-name which
will supply position information to a new macroexp-warn-and-return.
* lisp/emacs-lisp/cl-macs.el (cl-macs--strip-s-p-1)
(cl-macs--strip-symbol-positions): New functions to strip positions from
symbols in an expression. These duplicaate similarly named functions in
bytecomp.el.
* lisp/emacs-lisp/macroexpand.el (macroexp--warn-wrap): Calls
byte-compile-warn-x in place of byte-compile-warn.
(macroexp-warn-and-return): Commented out new position parameter _arg.
* src/.gdbinit: Add in code to handle symbols with position.
* src/alloc.c (XPNTR, set_symbol_name, valid_lisp_object_p, purecopy)
(mark_char_table, mark_object, survives_gc_p, symbol_uses_obj): Use
BARE_SYMBOL_P and XBARE_SYMBOL in place of the former SYMBOLP and XSYMBOL.
(build_symbol_with_pos): New function.
(Fgarbage_collect): Bind Qsymbols_with_pos_enabled to nil around the call to
garbage_collect.
* src/data.c (Ftype_of): Add case for PVEC_SYMBOL_WITH_POS.
(Fbare_symbol_p, Fsymbol_with_pos_p, Fbare_symbol, Fsymbol_with_pos_pos)
(Fposition_symbol): New functions.
(symbols_with_pos_enabled): New boolean variable.
* src/fns.c (internal_equal, hash_lookup): Handle symbols with position.
* src/keyboard.c (recursive_edit_1): Bind Qsymbols_with_pos_enabled and
Qprint_symbols_bare to nil.
* src/lisp.h (lisp_h_PSEUDOVECTORP): New macro.
(lisp_h_BASE_EQ): New name for the former lisp_h_EQ.
(lisp_h_EQ): Extended to handle symbols with position.
(lisp_h_NILP): Now uses BASE_EQ rather than EQ.
(lisp_h_SYMBOL_WITH_POS_P, lisp_h_BARE_SYMBOL_P): New macros.
(lisp_h_SYMBOLP): Redefined to handle symbols with position.
(BARE_SYMBOL_P, BASE_EQ): New macros.
(SYMBOLP (macro)): Removed.
(SYMBOLP (function), XSYMBOL, make_lisp_symbol, builtin_lisp_symbol)
(c_symbol_p): Moved to later in file.
(struct Lisp_Symbol_With_Pos): New data type.
(pvec_type): PVEC_SYMBOL_WITH_POS: New type code.
(PSEUDOVECTORP): Redefined to use the lisp_h_PSEUDOVECTORP.
(BARE_SYMBOL_P, SYMBOL_WITH_POS_P, SYMBOLP, XSYMBOL_WITH_POS, XBARE_SYMBOL)
(XSYMBOL, make_lisp_symbol, builtin_lisp_symbol, c_symbol_p, CHECK_SYMBOL)
(BASE_EQ): New functions, or functions moved from earlier in the file.
(SYMBOL_WITH_POS_SYM, SYMBOL_WITH_POS_POS): New INLINE functions.
* src/lread.c (read0, read1, read_list, read_vector, read_internal_start)
(list2): Add a new bool parameter locate_syms.
(Fread_positioning_symbols): New function.
(Fread_from_string, read_internal_start, read0, read1, read_list): Pass around
suitable values for locate_syms.
(read1): Build symbols with position when locate_syms is true.
* src/print.c (print_vectorlike): Add handling for PVEC_SYMBOL_WITH_POS.
(print_object): Replace EQ with BASE_EQ.
(print_symbols_bare): New boolean variable.
2021-11-29 11:19:31 +00:00
|
|
|
|
(byte-compile-warn-x fn "`%s' is a malformed function" fn)
|
2021-01-16 10:51:09 -05:00
|
|
|
|
form)
|
|
|
|
|
|
|
|
|
|
((guard (when for-effect
|
|
|
|
|
(if-let ((tmp (get fn 'side-effect-free)))
|
|
|
|
|
(or byte-compile-delete-errors
|
|
|
|
|
(eq tmp 'error-free)
|
|
|
|
|
(progn
|
First commit of scratch/correct-warning-pos.
This branch is intended to generate correct position information in warning
and error messages from the byte compiler, and is intended thereby to fix bugs
It introduces a new mechanism, the symbol with position. This is taken over
from the previous git branch scratch/accurate-warning-pos which was abandoned
for being too slow. The main difference in the current branch is that the
symbol `nil' is never given a position, thus speeding up NILP markedly.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-optimize-form-code-walker, byte-optimize-let-form, byte-optimize-while)
(byte-optimize-apply): Use byte-compile-warn-x in place of byte-compile-warn.
* lisp/emacs-lisp/bytecomp.el (byte-compile--form-stack): New variable.
(byte-compile-strip-s-p-1, byte-compile-strip-symbol-positions): New
functions.
(byte-compile-recurse-toplevel, byte-compile-initial-macro-environment)
(byte-compile-preprocess, byte-compile-macroexpand-declare-function): Bind
print-symbols-bare to non-nil.
(byte-compile--first-symbol, byte-compile--warning-source-offset): New
functions.
(byte-compile-warning-prefix): Modify to output two sets of position
information, the old (incorrect) set and the new set.
(byte-compile-warn): Strip positions from symbols before outputting.
(byte-compile-warn-x): New function which outputs a correct position supplied
in an argument.
(byte-compile-warn-obsolete, byte-compile-emit-callargs-warn)
(byte-compile-format-warn, byte-compile-nogroup-warn)
(byte-compile-arglist-warn, byte-compile-docstring-length-warn)
(byte-compile-warn-about-unresolved-functions, byte-compile-file)
(byte-compile--check-prefixed-var, byte-compile--declare-var)
(byte-compile-file-form-defvar-function, byte-compile-file-form-defmumble)
(byte-compile-check-lambda-list, byte-compile--warn-lexical-dynamic)
(byte-compile-lambda, byte-compile-form, byte-compile-normal-call)
(byte-compile-check-variable, byte-compile-free-vars-warn)
(byte-compile-subr-wrong-args, byte-compile-fset, byte-compile-set-default)
(byte-compile-condition-case, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-make-variable-buffer-local, byte-compile-define-symbol-prop)
(byte-compile-define-keymap): Replace byte-compile-warn with
byte-compile-warn-x.
(byte-compile-file, compile-defun): Bind symbols-with-pos-enabled to non-nil.
(compile-defun, byte-compile-from-buffer): Use `read-positioning-symbols'
rather than plain `read'.
(byte-compile-toplevel-file-form, byte-compile-form): Dynamically bind
byte-compile--form-stack.
(byte-compile-file-form-autoload, byte-compile-file-form-defvar)
(byte-compile-file-form-make-obsolete, byte-compile-lambda)
(byte-compile-push-constant, byte-compile-cond-jump-table)
(byte-compile-define-keymap, byte-compile-annotate-call-tree):
Strip positions from symbols where they are unwanted.
(byte-compile-file-form-defvar): Strip positions from symbols using
`bare-symbol'.
(byte-compile-file-form-defmumble): New variable bare-name, a version of name
without its position.
(byte-compile-lambda): Similarly, new variable bare-arglist.
(byte-compile-free-vars-warn): New argument arg supplying position information
to byte-compile-warn-x.
(byte-compile-push-constant): Manipulation of symbol positions.
(display-call-tree): Strip positions from symbols.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use)
(cconv--analyze-function, cconv-analyze-form): Replace use of
byte-compile-warn with byte-compile-warn-x.
* lisp/emacs-lisp/cl-generic.el (cl-defmethod): New variable org-name which
will supply position information to a new macroexp-warn-and-return.
* lisp/emacs-lisp/cl-macs.el (cl-macs--strip-s-p-1)
(cl-macs--strip-symbol-positions): New functions to strip positions from
symbols in an expression. These duplicaate similarly named functions in
bytecomp.el.
* lisp/emacs-lisp/macroexpand.el (macroexp--warn-wrap): Calls
byte-compile-warn-x in place of byte-compile-warn.
(macroexp-warn-and-return): Commented out new position parameter _arg.
* src/.gdbinit: Add in code to handle symbols with position.
* src/alloc.c (XPNTR, set_symbol_name, valid_lisp_object_p, purecopy)
(mark_char_table, mark_object, survives_gc_p, symbol_uses_obj): Use
BARE_SYMBOL_P and XBARE_SYMBOL in place of the former SYMBOLP and XSYMBOL.
(build_symbol_with_pos): New function.
(Fgarbage_collect): Bind Qsymbols_with_pos_enabled to nil around the call to
garbage_collect.
* src/data.c (Ftype_of): Add case for PVEC_SYMBOL_WITH_POS.
(Fbare_symbol_p, Fsymbol_with_pos_p, Fbare_symbol, Fsymbol_with_pos_pos)
(Fposition_symbol): New functions.
(symbols_with_pos_enabled): New boolean variable.
* src/fns.c (internal_equal, hash_lookup): Handle symbols with position.
* src/keyboard.c (recursive_edit_1): Bind Qsymbols_with_pos_enabled and
Qprint_symbols_bare to nil.
* src/lisp.h (lisp_h_PSEUDOVECTORP): New macro.
(lisp_h_BASE_EQ): New name for the former lisp_h_EQ.
(lisp_h_EQ): Extended to handle symbols with position.
(lisp_h_NILP): Now uses BASE_EQ rather than EQ.
(lisp_h_SYMBOL_WITH_POS_P, lisp_h_BARE_SYMBOL_P): New macros.
(lisp_h_SYMBOLP): Redefined to handle symbols with position.
(BARE_SYMBOL_P, BASE_EQ): New macros.
(SYMBOLP (macro)): Removed.
(SYMBOLP (function), XSYMBOL, make_lisp_symbol, builtin_lisp_symbol)
(c_symbol_p): Moved to later in file.
(struct Lisp_Symbol_With_Pos): New data type.
(pvec_type): PVEC_SYMBOL_WITH_POS: New type code.
(PSEUDOVECTORP): Redefined to use the lisp_h_PSEUDOVECTORP.
(BARE_SYMBOL_P, SYMBOL_WITH_POS_P, SYMBOLP, XSYMBOL_WITH_POS, XBARE_SYMBOL)
(XSYMBOL, make_lisp_symbol, builtin_lisp_symbol, c_symbol_p, CHECK_SYMBOL)
(BASE_EQ): New functions, or functions moved from earlier in the file.
(SYMBOL_WITH_POS_SYM, SYMBOL_WITH_POS_POS): New INLINE functions.
* src/lread.c (read0, read1, read_list, read_vector, read_internal_start)
(list2): Add a new bool parameter locate_syms.
(Fread_positioning_symbols): New function.
(Fread_from_string, read_internal_start, read0, read1, read_list): Pass around
suitable values for locate_syms.
(read1): Build symbols with position when locate_syms is true.
* src/print.c (print_vectorlike): Add handling for PVEC_SYMBOL_WITH_POS.
(print_object): Replace EQ with BASE_EQ.
(print_symbols_bare): New boolean variable.
2021-11-29 11:19:31 +00:00
|
|
|
|
(byte-compile-warn-x
|
|
|
|
|
form
|
|
|
|
|
"value returned from %s is unused"
|
|
|
|
|
form)
|
2021-01-16 10:51:09 -05:00
|
|
|
|
nil)))))
|
|
|
|
|
(byte-compile-log " %s called for effect; deleted" fn)
|
|
|
|
|
;; appending a nil here might not be necessary, but it can't hurt.
|
|
|
|
|
(byte-optimize-form
|
|
|
|
|
(cons 'progn (append (cdr form) '(nil))) t))
|
|
|
|
|
|
|
|
|
|
(_
|
|
|
|
|
;; Otherwise, no args can be considered to be for-effect,
|
|
|
|
|
;; even if the called function is for-effect, because we
|
|
|
|
|
;; don't know anything about that function.
|
|
|
|
|
(let ((form (cons fn (mapcar #'byte-optimize-form (cdr form)))))
|
|
|
|
|
(if (get fn 'pure)
|
|
|
|
|
(byte-optimize-constant-args form)
|
|
|
|
|
form))))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2021-07-28 21:12:27 +02:00
|
|
|
|
(defun byte-optimize-one-form (form &optional for-effect)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
"The source-level pass of the optimizer."
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; Make optimizer aware of lexical arguments.
|
2021-07-28 21:12:27 +02:00
|
|
|
|
(let ((byte-optimize--lexvars
|
|
|
|
|
(mapcar (lambda (v) (list (car v) t))
|
|
|
|
|
byte-compile--lexical-environment)))
|
|
|
|
|
(byte-optimize-form form for-effect)))
|
|
|
|
|
|
|
|
|
|
(defun byte-optimize-form (form &optional for-effect)
|
2021-02-11 17:34:17 +01:00
|
|
|
|
(while
|
|
|
|
|
(progn
|
|
|
|
|
;; First, optimize all sub-forms of this one.
|
|
|
|
|
(setq form (byte-optimize-form-code-walker form for-effect))
|
|
|
|
|
|
2022-07-13 13:00:31 +02:00
|
|
|
|
;; If a form-specific optimizer is available, run it and start over
|
2021-02-11 17:34:17 +01:00
|
|
|
|
;; until a fixpoint has been reached.
|
|
|
|
|
(and (consp form)
|
|
|
|
|
(symbolp (car form))
|
|
|
|
|
(let ((opt (function-get (car form) 'byte-optimizer)))
|
|
|
|
|
(and opt
|
|
|
|
|
(let ((old form)
|
|
|
|
|
(new (funcall opt form)))
|
|
|
|
|
(byte-compile-log " %s\t==>\t%s" old new)
|
|
|
|
|
(setq form new)
|
|
|
|
|
(not (eq new old))))))))
|
2021-07-21 10:54:43 +02:00
|
|
|
|
form)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2021-07-30 13:44:07 +02:00
|
|
|
|
(defun byte-optimize--rename-var-body (var new-var body)
|
|
|
|
|
"Replace VAR with NEW-VAR in BODY."
|
|
|
|
|
(mapcar (lambda (form) (byte-optimize--rename-var var new-var form)) body))
|
|
|
|
|
|
|
|
|
|
(defun byte-optimize--rename-var (var new-var form)
|
|
|
|
|
"Replace VAR with NEW-VAR in FORM."
|
Byte compiler: Prevent special forms' symbols being replaced by bare symbols
These are symbols with position from source code, which should not be replaced
by bare symbols in, e.g., optimization functions.
* lisp/Makefile.in: (BYTE_COMPILE_FLAGS, compile-first case): Set
max-specpdl-size to 5000 for the benefit of lisp/emacs-lisp/comp.el.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker)
(byte-optimize--rename-var, byte-optimize-if, byte-optimize-letX)
* lisp/emacs-lisp/bytecomp.el (byte-compile-recurse-toplevel)
(byte-compile-lambda)
* lisp/emacs-lisp/cconv.el (cconv-convert)
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Preserve, e.g., (car
form) in the byte compiler, when this form's car is a symbol with position of
a special form, rather than replacing the symbol with a bare symbol, e.g.
'cond.
2022-04-22 19:11:31 +00:00
|
|
|
|
(let ((fn (car-safe form)))
|
|
|
|
|
(pcase form
|
|
|
|
|
((pred symbolp) (if (eq form var) new-var form))
|
|
|
|
|
(`(setq . ,args)
|
|
|
|
|
(let ((new-args nil))
|
|
|
|
|
(while args
|
|
|
|
|
(push (byte-optimize--rename-var var new-var (car args)) new-args)
|
|
|
|
|
(push (byte-optimize--rename-var var new-var (cadr args)) new-args)
|
|
|
|
|
(setq args (cddr args)))
|
|
|
|
|
`(,fn . ,(nreverse new-args))))
|
|
|
|
|
;; In binding constructs like `let', `let*' and `condition-case' we
|
|
|
|
|
;; rename everything for simplicity, even new bindings named VAR.
|
|
|
|
|
(`(,(and head (or 'let 'let*)) ,bindings . ,body)
|
|
|
|
|
`(,head
|
|
|
|
|
,(mapcar (lambda (b) (byte-optimize--rename-var-body var new-var b))
|
|
|
|
|
bindings)
|
|
|
|
|
,@(byte-optimize--rename-var-body var new-var body)))
|
|
|
|
|
(`(condition-case ,res-var ,protected-form . ,handlers)
|
|
|
|
|
`(,fn ,(byte-optimize--rename-var var new-var res-var)
|
|
|
|
|
,(byte-optimize--rename-var var new-var protected-form)
|
|
|
|
|
,@(mapcar (lambda (h)
|
|
|
|
|
(cons (car h)
|
|
|
|
|
(byte-optimize--rename-var-body var new-var (cdr h))))
|
|
|
|
|
handlers)))
|
|
|
|
|
(`(internal-make-closure ,vars ,env . ,rest)
|
|
|
|
|
`(,fn
|
|
|
|
|
,vars ,(byte-optimize--rename-var-body var new-var env) . ,rest))
|
|
|
|
|
(`(defvar ,name . ,rest)
|
|
|
|
|
;; NAME is not renamed here; we only care about lexical variables.
|
|
|
|
|
`(,fn ,name . ,(byte-optimize--rename-var-body var new-var rest)))
|
|
|
|
|
|
|
|
|
|
(`(cond . ,clauses)
|
|
|
|
|
`(,fn ,@(mapcar (lambda (c)
|
|
|
|
|
(byte-optimize--rename-var-body var new-var c))
|
|
|
|
|
clauses)))
|
|
|
|
|
|
|
|
|
|
(`(function . ,_) form)
|
|
|
|
|
(`(quote . ,_) form)
|
|
|
|
|
(`(lambda . ,_) form)
|
|
|
|
|
|
|
|
|
|
;; Function calls and special forms not handled above.
|
|
|
|
|
(`(,head . ,args)
|
|
|
|
|
`(,head . ,(byte-optimize--rename-var-body var new-var args)))
|
|
|
|
|
(_ form))))
|
2021-07-30 13:44:07 +02:00
|
|
|
|
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(defun byte-optimize-let-form (head form for-effect)
|
|
|
|
|
;; Recursively enter the optimizer for the bindings and body
|
|
|
|
|
;; of a let or let*. This for depth-firstness: forms that
|
|
|
|
|
;; are more deeply nested are optimized first.
|
2021-07-30 12:22:01 +02:00
|
|
|
|
(if lexical-binding
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(let* ((byte-optimize--lexvars byte-optimize--lexvars)
|
2021-07-30 13:44:07 +02:00
|
|
|
|
(byte-optimize--aliased-vars byte-optimize--aliased-vars)
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(new-lexvars nil)
|
2021-07-30 13:44:07 +02:00
|
|
|
|
(new-aliased-vars nil)
|
|
|
|
|
(let-vars nil)
|
|
|
|
|
(body (cdr form))
|
|
|
|
|
(bindings (car form)))
|
|
|
|
|
(while bindings
|
|
|
|
|
(let* ((binding (car bindings))
|
|
|
|
|
(name (car binding))
|
|
|
|
|
(expr (byte-optimize-form (cadr binding) nil)))
|
|
|
|
|
(setq bindings (cdr bindings))
|
|
|
|
|
(when (and (eq head 'let*)
|
|
|
|
|
(memq name byte-optimize--aliased-vars))
|
|
|
|
|
;; New variable shadows an aliased variable -- α-rename
|
|
|
|
|
;; it in this and all subsequent bindings.
|
|
|
|
|
(let ((new-name (make-symbol (symbol-name name))))
|
|
|
|
|
(setq bindings
|
|
|
|
|
(mapcar (lambda (b)
|
|
|
|
|
(list (byte-optimize--rename-var
|
|
|
|
|
name new-name (car b))
|
|
|
|
|
(byte-optimize--rename-var
|
|
|
|
|
name new-name (cadr b))))
|
|
|
|
|
bindings))
|
|
|
|
|
(setq body (byte-optimize--rename-var-body name new-name body))
|
|
|
|
|
(setq name new-name)))
|
|
|
|
|
(let* ((aliased nil)
|
|
|
|
|
(value (and
|
|
|
|
|
(or (byte-optimize--substitutable-p expr)
|
|
|
|
|
;; Aliasing another lexvar.
|
|
|
|
|
(setq aliased
|
|
|
|
|
(and (symbolp expr)
|
|
|
|
|
(assq expr byte-optimize--lexvars))))
|
|
|
|
|
(list expr)))
|
|
|
|
|
(lexical (not (or (special-variable-p name)
|
|
|
|
|
(memq name byte-compile-bound-variables)
|
|
|
|
|
(memq name byte-optimize--dynamic-vars))))
|
|
|
|
|
(lexinfo (and lexical (cons name (cons nil value)))))
|
|
|
|
|
(push (cons name (cons expr (cdr lexinfo))) let-vars)
|
|
|
|
|
(when lexinfo
|
|
|
|
|
(push lexinfo (if (eq head 'let*)
|
|
|
|
|
byte-optimize--lexvars
|
|
|
|
|
new-lexvars)))
|
|
|
|
|
(when aliased
|
|
|
|
|
(push expr (if (eq head 'let*)
|
|
|
|
|
byte-optimize--aliased-vars
|
|
|
|
|
new-aliased-vars))))))
|
|
|
|
|
|
|
|
|
|
(setq byte-optimize--aliased-vars
|
|
|
|
|
(append new-aliased-vars byte-optimize--aliased-vars))
|
|
|
|
|
(when (and (eq head 'let) byte-optimize--aliased-vars)
|
|
|
|
|
;; Find new variables that shadow aliased variables.
|
|
|
|
|
(let ((shadowing-vars nil))
|
|
|
|
|
(dolist (lexvar new-lexvars)
|
|
|
|
|
(let ((name (car lexvar)))
|
|
|
|
|
(when (and (memq name byte-optimize--aliased-vars)
|
|
|
|
|
(not (memq name shadowing-vars)))
|
|
|
|
|
(push name shadowing-vars))))
|
|
|
|
|
;; α-rename them
|
|
|
|
|
(dolist (name shadowing-vars)
|
|
|
|
|
(let ((new-name (make-symbol (symbol-name name))))
|
|
|
|
|
(setq new-lexvars
|
|
|
|
|
(mapcar (lambda (lexvar)
|
|
|
|
|
(if (eq (car lexvar) name)
|
|
|
|
|
(cons new-name (cdr lexvar))
|
|
|
|
|
lexvar))
|
|
|
|
|
new-lexvars))
|
|
|
|
|
(setq let-vars
|
|
|
|
|
(mapcar (lambda (v)
|
|
|
|
|
(if (eq (car v) name)
|
|
|
|
|
(cons new-name (cdr v))
|
|
|
|
|
v))
|
|
|
|
|
let-vars))
|
|
|
|
|
(setq body (byte-optimize--rename-var-body
|
|
|
|
|
name new-name body))))))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(setq byte-optimize--lexvars
|
|
|
|
|
(append new-lexvars byte-optimize--lexvars))
|
|
|
|
|
;; Walk the body expressions, which may mutate some of the records,
|
|
|
|
|
;; and generate new bindings that exclude unused variables.
|
2021-02-10 14:26:49 +01:00
|
|
|
|
(let* ((byte-optimize--dynamic-vars byte-optimize--dynamic-vars)
|
2021-07-30 13:44:07 +02:00
|
|
|
|
(opt-body (byte-optimize-body body for-effect))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(bindings nil))
|
|
|
|
|
(dolist (var let-vars)
|
2021-02-07 10:35:36 +01:00
|
|
|
|
;; VAR is (NAME EXPR [KEEP [VALUE]])
|
2021-09-22 11:03:30 +02:00
|
|
|
|
(when (or (not (nthcdr 3 var)) (nth 2 var)
|
|
|
|
|
byte-optimize--inhibit-outside-loop-constprop)
|
|
|
|
|
;; Value not present, or variable marked to be kept,
|
|
|
|
|
;; or we are in the loop discovery phase: keep the binding.
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(push (list (nth 0 var) (nth 1 var)) bindings)))
|
|
|
|
|
(cons bindings opt-body)))
|
|
|
|
|
|
|
|
|
|
;; With dynamic binding, no substitutions are in effect.
|
|
|
|
|
(let ((byte-optimize--lexvars nil))
|
|
|
|
|
(cons
|
|
|
|
|
(mapcar (lambda (binding)
|
2022-06-06 11:10:05 +02:00
|
|
|
|
(list (car binding)
|
|
|
|
|
(byte-optimize-form (nth 1 binding) nil)))
|
Constprop of lexical variables
Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible. Example:
(let ((x (+ 2 3))) (f x)) => (f 5)
This reduces code size, eliminates stack operations, and enables
further optimisations. The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.
* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
2021-02-06 18:34:45 +01:00
|
|
|
|
(car form))
|
|
|
|
|
(byte-optimize-body (cdr form) for-effect)))))
|
|
|
|
|
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-body (forms all-for-effect)
|
Try and fix w32 build; misc cleanup.
* lisp/subr.el (apply-partially): Move from subr.el; don't use lexical-let.
(eval-after-load): Obey lexical-binding.
* lisp/simple.el (apply-partially): Move to subr.el.
* lisp/makefile.w32-in: Match changes in Makefile.in.
(BIG_STACK_DEPTH, BIG_STACK_OPTS, BYTE_COMPILE_FLAGS): New vars.
(.el.elc, compile-CMD, compile-SH, compile-always-CMD)
(compile-always-SH, compile-calc-CMD, compile-calc-SH): Use them.
(COMPILE_FIRST): Add pcase, macroexp, and cconv.
* lisp/emacs-lisp/macroexp.el (macroexpand-all-1): Silence warning about
calling CL's `compiler-macroexpand'.
* lisp/emacs-lisp/bytecomp.el (byte-compile-preprocess): New function.
(byte-compile-initial-macro-environment)
(byte-compile-toplevel-file-form, byte-compile, byte-compile-sexp): Use it.
(byte-compile-eval, byte-compile-eval-before-compile): Obey lexical-binding.
(byte-compile--for-effect): Rename from `for-effect'.
(display-call-tree): Use case.
* lisp/emacs-lisp/byte-opt.el (for-effect): Don't declare as dynamic.
(byte-optimize-form-code-walker, byte-optimize-form):
Revert to old arg name.
* lisp/Makefile.in (BYTE_COMPILE_FLAGS): New var.
(compile-onefile, .el.elc, compile-calc, recompile): Use it.
2011-03-11 22:32:43 -05:00
|
|
|
|
;; Optimize the cdr of a progn or implicit progn; all forms is a list of
|
1992-07-10 22:06:47 +00:00
|
|
|
|
;; forms, all but the last of which are optimized with the assumption that
|
|
|
|
|
;; they are being called for effect. the last is for-effect as well if
|
|
|
|
|
;; all-for-effect is true. returns a new list of forms.
|
|
|
|
|
(let ((rest forms)
|
|
|
|
|
(result nil)
|
|
|
|
|
fe new)
|
|
|
|
|
(while rest
|
|
|
|
|
(setq fe (or all-for-effect (cdr rest)))
|
|
|
|
|
(setq new (and (car rest) (byte-optimize-form (car rest) fe)))
|
2021-09-06 14:41:26 +02:00
|
|
|
|
(when (and (consp new) (eq (car new) 'progn))
|
|
|
|
|
;; Flatten `progn' form into the body.
|
|
|
|
|
(setq result (append (reverse (cdr new)) result))
|
|
|
|
|
(setq new (pop result)))
|
|
|
|
|
(when (or new (not fe))
|
|
|
|
|
(setq result (cons new result)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(setq rest (cdr rest)))
|
|
|
|
|
(nreverse result)))
|
|
|
|
|
|
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; some source-level optimizers
|
|
|
|
|
;;
|
|
|
|
|
;; when writing optimizers, be VERY careful that the optimizer returns
|
|
|
|
|
;; something not EQ to its argument if and ONLY if it has made a change.
|
|
|
|
|
;; This implies that you cannot simply destructively modify the list;
|
|
|
|
|
;; you must return something not EQ to it if you make an optimization.
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2022-08-12 20:11:52 +02:00
|
|
|
|
(defsubst byte-opt--bool-value-form (form)
|
|
|
|
|
"The form in FORM that yields its boolean value, possibly FORM itself."
|
|
|
|
|
(while (let ((head (car-safe form)))
|
|
|
|
|
(cond ((memq head '( progn inline save-excursion save-restriction
|
|
|
|
|
save-current-buffer))
|
2022-08-21 16:17:45 +02:00
|
|
|
|
(setq form (car (last (cdr form))))
|
2022-08-12 20:11:52 +02:00
|
|
|
|
t)
|
2022-08-21 16:17:45 +02:00
|
|
|
|
((memq head '(let let*))
|
2022-08-12 20:11:52 +02:00
|
|
|
|
(setq form (car (last (cddr form))))
|
|
|
|
|
t)
|
|
|
|
|
((memq head '( prog1 unwind-protect copy-sequence identity
|
|
|
|
|
reverse nreverse sort))
|
|
|
|
|
(setq form (nth 1 form))
|
|
|
|
|
t)
|
2022-09-25 17:47:39 +02:00
|
|
|
|
((memq head '(mapc setq setcar setcdr puthash set))
|
2022-08-12 20:11:52 +02:00
|
|
|
|
(setq form (nth 2 form))
|
2022-08-21 16:17:45 +02:00
|
|
|
|
t)
|
|
|
|
|
((memq head '(aset put function-put))
|
|
|
|
|
(setq form (nth 3 form))
|
2022-08-12 20:11:52 +02:00
|
|
|
|
t))))
|
|
|
|
|
form)
|
|
|
|
|
|
|
|
|
|
(defun byte-compile-trueconstp (form)
|
2007-11-13 16:10:14 +00:00
|
|
|
|
"Return non-nil if FORM always evaluates to a non-nil value."
|
2022-08-12 20:11:52 +02:00
|
|
|
|
(setq form (byte-opt--bool-value-form form))
|
2007-11-13 16:10:14 +00:00
|
|
|
|
(cond ((consp form)
|
2022-08-12 20:11:52 +02:00
|
|
|
|
(let ((head (car form)))
|
|
|
|
|
;; FIXME: Lots of other expressions are statically non-nil.
|
|
|
|
|
(cond ((memq head '(quote function)) (cadr form))
|
|
|
|
|
((eq head 'list) (cdr form))
|
|
|
|
|
((memq head
|
|
|
|
|
;; FIXME: Replace this list with a function property?
|
2022-12-15 11:22:06 +01:00
|
|
|
|
'( lambda internal-make-closure
|
|
|
|
|
length safe-length cons
|
2022-08-18 12:33:40 +02:00
|
|
|
|
string unibyte-string make-string concat
|
|
|
|
|
format format-message
|
2022-08-12 20:11:52 +02:00
|
|
|
|
substring substring-no-properties string-replace
|
|
|
|
|
replace-regexp-in-string symbol-name make-symbol
|
2022-08-21 16:17:45 +02:00
|
|
|
|
compare-strings string-distance
|
2022-08-12 20:11:52 +02:00
|
|
|
|
mapconcat
|
|
|
|
|
vector make-vector vconcat make-record record
|
|
|
|
|
regexp-quote regexp-opt
|
|
|
|
|
buffer-string buffer-substring
|
|
|
|
|
buffer-substring-no-properties
|
2022-08-21 16:17:45 +02:00
|
|
|
|
current-buffer buffer-size get-buffer-create
|
2022-08-18 12:33:40 +02:00
|
|
|
|
point point-min point-max buffer-end count-lines
|
2022-08-21 16:17:45 +02:00
|
|
|
|
following-char preceding-char get-byte max-char
|
2022-08-18 12:33:40 +02:00
|
|
|
|
region-beginning region-end
|
|
|
|
|
line-beginning-position line-end-position
|
2022-08-21 16:17:45 +02:00
|
|
|
|
pos-bol pos-eol
|
2022-08-18 12:33:40 +02:00
|
|
|
|
+ - * / % 1+ 1- min max abs mod expt logb
|
|
|
|
|
logand logior logxor lognot ash logcount
|
|
|
|
|
floor ceiling round truncate
|
|
|
|
|
sqrt sin cos tan asin acos atan exp log copysign
|
|
|
|
|
ffloor fceiling fround ftruncate float
|
|
|
|
|
ldexp frexp
|
2022-08-12 20:11:52 +02:00
|
|
|
|
number-to-string string-to-number
|
2022-08-18 12:33:40 +02:00
|
|
|
|
int-to-string char-to-string
|
|
|
|
|
prin1-to-string read-from-string
|
2022-08-12 20:11:52 +02:00
|
|
|
|
byte-to-string string-to-vector string-to-char
|
2022-08-18 12:33:40 +02:00
|
|
|
|
capitalize upcase downcase
|
|
|
|
|
propertize
|
|
|
|
|
string-as-multibyte string-as-unibyte
|
|
|
|
|
string-to-multibyte string-to-unibyte
|
|
|
|
|
string-make-multibyte string-make-unibyte
|
2022-08-21 16:17:45 +02:00
|
|
|
|
string-width char-width
|
2022-08-18 12:33:40 +02:00
|
|
|
|
make-hash-table hash-table-count
|
|
|
|
|
unibyte-char-to-multibyte multibyte-char-to-unibyte
|
|
|
|
|
sxhash sxhash-equal sxhash-eq sxhash-eql
|
|
|
|
|
sxhash-equal-including-properties
|
|
|
|
|
make-marker copy-marker point-marker mark-marker
|
2022-09-25 17:47:39 +02:00
|
|
|
|
set-marker
|
2022-08-21 16:17:45 +02:00
|
|
|
|
kbd key-description
|
2022-08-12 20:11:52 +02:00
|
|
|
|
always))
|
|
|
|
|
t)
|
|
|
|
|
((eq head 'if)
|
|
|
|
|
(and (byte-compile-trueconstp (nth 2 form))
|
|
|
|
|
(byte-compile-trueconstp (car (last (cdddr form))))))
|
|
|
|
|
((memq head '(not null))
|
|
|
|
|
(byte-compile-nilconstp (cadr form)))
|
|
|
|
|
((eq head 'or)
|
|
|
|
|
(and (cdr form)
|
|
|
|
|
(byte-compile-trueconstp (car (last (cdr form)))))))))
|
2007-11-13 16:10:14 +00:00
|
|
|
|
((not (symbolp form)))
|
|
|
|
|
((eq form t))
|
|
|
|
|
((keywordp form))))
|
|
|
|
|
|
2022-08-12 20:11:52 +02:00
|
|
|
|
(defun byte-compile-nilconstp (form)
|
2007-11-13 16:10:14 +00:00
|
|
|
|
"Return non-nil if FORM always evaluates to a nil value."
|
2022-08-12 20:11:52 +02:00
|
|
|
|
(setq form (byte-opt--bool-value-form form))
|
2022-09-29 15:19:01 +02:00
|
|
|
|
(or (not form) ; assume (quote nil) always being normalized to nil
|
2022-08-12 20:11:52 +02:00
|
|
|
|
(and (consp form)
|
|
|
|
|
(let ((head (car form)))
|
|
|
|
|
;; FIXME: There are many other expressions that are statically nil.
|
|
|
|
|
(cond ((memq head '(while ignore)) t)
|
|
|
|
|
((eq head 'if)
|
|
|
|
|
(and (byte-compile-nilconstp (nth 2 form))
|
|
|
|
|
(byte-compile-nilconstp (car (last (cdddr form))))))
|
|
|
|
|
((memq head '(not null))
|
|
|
|
|
(byte-compile-trueconstp (cadr form)))
|
|
|
|
|
((eq head 'and)
|
|
|
|
|
(and (cdr form)
|
|
|
|
|
(byte-compile-nilconstp (car (last (cdr form)))))))))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2018-03-23 12:57:39 -07:00
|
|
|
|
;; If the function is being called with constant integer args,
|
2003-02-04 13:24:35 +00:00
|
|
|
|
;; evaluate as much as possible at compile-time. This optimizer
|
2018-03-23 12:57:39 -07:00
|
|
|
|
;; assumes that the function is associative, like min or max.
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-optimize-associative-math (form)
|
|
|
|
|
(let ((args nil)
|
|
|
|
|
(constants nil)
|
|
|
|
|
(rest (cdr form)))
|
|
|
|
|
(while rest
|
2018-03-23 12:57:39 -07:00
|
|
|
|
(if (integerp (car rest))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(setq constants (cons (car rest) constants))
|
|
|
|
|
(setq args (cons (car rest) args)))
|
|
|
|
|
(setq rest (cdr rest)))
|
|
|
|
|
(if (cdr constants)
|
2020-08-03 16:29:06 +02:00
|
|
|
|
(let ((const (apply (car form) (nreverse constants))))
|
|
|
|
|
(if args
|
|
|
|
|
(append (list (car form) const)
|
|
|
|
|
(nreverse args))
|
|
|
|
|
const))
|
|
|
|
|
form)))
|
|
|
|
|
|
|
|
|
|
(defun byte-optimize-min-max (form)
|
|
|
|
|
"Optimize `min' and `max'."
|
|
|
|
|
(let ((opt (byte-optimize-associative-math form)))
|
|
|
|
|
(if (and (consp opt) (memq (car opt) '(min max))
|
|
|
|
|
(= (length opt) 4))
|
|
|
|
|
;; (OP x y z) -> (OP (OP x y) z), in order to use binary byte ops.
|
|
|
|
|
(list (car opt)
|
|
|
|
|
(list (car opt) (nth 1 opt) (nth 2 opt))
|
|
|
|
|
(nth 3 opt))
|
|
|
|
|
opt)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
Relax portable number check in byte compiler (bug#42147)
With bignums, the set of representable integers is no longer
platform-dependent, and since we use nothing but IEEE754 64-bit
floats, all numbers are now portable. Take advantage of this fact
to simplify constant-folding in the byte compiler, allowing it to
be applied more widely.
* lisp/emacs-lisp/byte-opt.el (byte-opt--portable-max)
(byte-opt--portable-min, byte-opt--portable-numberp): Remove.
(byte-opt--arith-reduce, byte-optimize-minus, byte-optimize-1+)
(byte-optimize-1-): Simplify: any number will do, and if N is a
number, then so are -N, N+1 and N-1.
2020-07-03 20:13:50 +02:00
|
|
|
|
;; Use OP to reduce any leading prefix of constant numbers in the list
|
|
|
|
|
;; (cons ACCUM ARGS) down to a single number, and return the
|
2018-03-26 17:03:54 -07:00
|
|
|
|
;; resulting list A of arguments. The idea is that applying OP to A
|
|
|
|
|
;; is equivalent to (but likely more efficient than) applying OP to
|
|
|
|
|
;; (cons ACCUM ARGS), on any Emacs platform. Do not make any special
|
|
|
|
|
;; provision for (- X) or (/ X); for example, it is the caller’s
|
|
|
|
|
;; responsibility that (- 1 0) should not be "optimized" to (- 1).
|
|
|
|
|
(defun byte-opt--arith-reduce (op accum args)
|
Relax portable number check in byte compiler (bug#42147)
With bignums, the set of representable integers is no longer
platform-dependent, and since we use nothing but IEEE754 64-bit
floats, all numbers are now portable. Take advantage of this fact
to simplify constant-folding in the byte compiler, allowing it to
be applied more widely.
* lisp/emacs-lisp/byte-opt.el (byte-opt--portable-max)
(byte-opt--portable-min, byte-opt--portable-numberp): Remove.
(byte-opt--arith-reduce, byte-optimize-minus, byte-optimize-1+)
(byte-optimize-1-): Simplify: any number will do, and if N is a
number, then so are -N, N+1 and N-1.
2020-07-03 20:13:50 +02:00
|
|
|
|
(when (numberp accum)
|
2018-03-26 17:03:54 -07:00
|
|
|
|
(let (accum1)
|
Relax portable number check in byte compiler (bug#42147)
With bignums, the set of representable integers is no longer
platform-dependent, and since we use nothing but IEEE754 64-bit
floats, all numbers are now portable. Take advantage of this fact
to simplify constant-folding in the byte compiler, allowing it to
be applied more widely.
* lisp/emacs-lisp/byte-opt.el (byte-opt--portable-max)
(byte-opt--portable-min, byte-opt--portable-numberp): Remove.
(byte-opt--arith-reduce, byte-optimize-minus, byte-optimize-1+)
(byte-optimize-1-): Simplify: any number will do, and if N is a
number, then so are -N, N+1 and N-1.
2020-07-03 20:13:50 +02:00
|
|
|
|
(while (and (numberp (car args))
|
|
|
|
|
(numberp
|
2018-03-26 17:03:54 -07:00
|
|
|
|
(setq accum1 (condition-case ()
|
|
|
|
|
(funcall op accum (car args))
|
|
|
|
|
(error))))
|
|
|
|
|
(= accum1 (funcall op (float accum) (car args))))
|
|
|
|
|
(setq accum accum1)
|
|
|
|
|
(setq args (cdr args)))))
|
|
|
|
|
(cons accum args))
|
|
|
|
|
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-optimize-plus (form)
|
2018-03-26 17:03:54 -07:00
|
|
|
|
(let ((args (remq 0 (byte-opt--arith-reduce #'+ 0 (cdr form)))))
|
2008-11-21 18:51:48 +00:00
|
|
|
|
(cond
|
2018-03-26 17:03:54 -07:00
|
|
|
|
;; (+) -> 0
|
|
|
|
|
((null args) 0)
|
|
|
|
|
;; (+ n) -> n, where n is a number
|
|
|
|
|
((and (null (cdr args)) (numberp (car args))) (car args))
|
2008-11-21 18:51:48 +00:00
|
|
|
|
;; (+ x 1) --> (1+ x) and (+ x -1) --> (1- x).
|
2018-03-26 17:03:54 -07:00
|
|
|
|
((and (null (cddr args)) (or (memq 1 args) (memq -1 args)))
|
|
|
|
|
(let* ((arg1 (car args)) (arg2 (cadr args))
|
|
|
|
|
(integer-is-first (memq arg1 '(1 -1)))
|
|
|
|
|
(integer (if integer-is-first arg1 arg2))
|
|
|
|
|
(other (if integer-is-first arg2 arg1)))
|
|
|
|
|
(list (if (eq integer 1) '1+ '1-) other)))
|
2020-07-25 19:12:26 +02:00
|
|
|
|
;; (+ x y z) -> (+ (+ x y) z)
|
|
|
|
|
((= (length args) 3)
|
|
|
|
|
`(+ ,(byte-optimize-plus `(+ ,(car args) ,(cadr args))) ,@(cddr args)))
|
2018-03-26 17:03:54 -07:00
|
|
|
|
;; not further optimized
|
|
|
|
|
((equal args (cdr form)) form)
|
|
|
|
|
(t (cons '+ args)))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-minus (form)
|
2018-03-26 17:03:54 -07:00
|
|
|
|
(let ((args (cdr form)))
|
|
|
|
|
(if (and (cdr args)
|
|
|
|
|
(null (cdr (setq args (byte-opt--arith-reduce
|
|
|
|
|
#'- (car args) (cdr args)))))
|
|
|
|
|
(numberp (car args)))
|
|
|
|
|
;; The entire argument list reduced to a constant; return it.
|
|
|
|
|
(car args)
|
|
|
|
|
;; Remove non-leading zeros, except for (- x 0).
|
|
|
|
|
(when (memq 0 (cdr args))
|
|
|
|
|
(setq args (cons (car args) (or (remq 0 (cdr args)) (list 0)))))
|
|
|
|
|
(cond
|
|
|
|
|
;; (- x 1) --> (1- x)
|
|
|
|
|
((equal (cdr args) '(1))
|
|
|
|
|
(list '1- (car args)))
|
|
|
|
|
;; (- x -1) --> (1+ x)
|
|
|
|
|
((equal (cdr args) '(-1))
|
|
|
|
|
(list '1+ (car args)))
|
Relax portable number check in byte compiler (bug#42147)
With bignums, the set of representable integers is no longer
platform-dependent, and since we use nothing but IEEE754 64-bit
floats, all numbers are now portable. Take advantage of this fact
to simplify constant-folding in the byte compiler, allowing it to
be applied more widely.
* lisp/emacs-lisp/byte-opt.el (byte-opt--portable-max)
(byte-opt--portable-min, byte-opt--portable-numberp): Remove.
(byte-opt--arith-reduce, byte-optimize-minus, byte-optimize-1+)
(byte-optimize-1-): Simplify: any number will do, and if N is a
number, then so are -N, N+1 and N-1.
2020-07-03 20:13:50 +02:00
|
|
|
|
;; (- n) -> -n, where n and -n are constant numbers.
|
2018-03-26 17:03:54 -07:00
|
|
|
|
;; This must be done separately since byte-opt--arith-reduce
|
|
|
|
|
;; is not applied to (- n).
|
|
|
|
|
((and (null (cdr args))
|
Relax portable number check in byte compiler (bug#42147)
With bignums, the set of representable integers is no longer
platform-dependent, and since we use nothing but IEEE754 64-bit
floats, all numbers are now portable. Take advantage of this fact
to simplify constant-folding in the byte compiler, allowing it to
be applied more widely.
* lisp/emacs-lisp/byte-opt.el (byte-opt--portable-max)
(byte-opt--portable-min, byte-opt--portable-numberp): Remove.
(byte-opt--arith-reduce, byte-optimize-minus, byte-optimize-1+)
(byte-optimize-1-): Simplify: any number will do, and if N is a
number, then so are -N, N+1 and N-1.
2020-07-03 20:13:50 +02:00
|
|
|
|
(numberp (car args)))
|
2018-03-26 17:03:54 -07:00
|
|
|
|
(- (car args)))
|
2020-07-25 19:12:26 +02:00
|
|
|
|
;; (- x y z) -> (- (- x y) z)
|
|
|
|
|
((= (length args) 3)
|
|
|
|
|
`(- ,(byte-optimize-minus `(- ,(car args) ,(cadr args))) ,@(cddr args)))
|
2018-03-26 17:03:54 -07:00
|
|
|
|
;; not further optimized
|
|
|
|
|
((equal args (cdr form)) form)
|
|
|
|
|
(t (cons '- args))))))
|
|
|
|
|
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-optimize-multiply (form)
|
2018-03-26 17:03:54 -07:00
|
|
|
|
(let* ((args (remq 1 (byte-opt--arith-reduce #'* 1 (cdr form)))))
|
|
|
|
|
(cond
|
|
|
|
|
;; (*) -> 1
|
|
|
|
|
((null args) 1)
|
|
|
|
|
;; (* n) -> n, where n is a number
|
|
|
|
|
((and (null (cdr args)) (numberp (car args))) (car args))
|
2020-07-25 19:12:26 +02:00
|
|
|
|
;; (* x y z) -> (* (* x y) z)
|
|
|
|
|
((= (length args) 3)
|
|
|
|
|
`(* ,(byte-optimize-multiply `(* ,(car args) ,(cadr args)))
|
|
|
|
|
,@(cddr args)))
|
2018-03-26 17:03:54 -07:00
|
|
|
|
;; not further optimized
|
|
|
|
|
((equal args (cdr form)) form)
|
|
|
|
|
(t (cons '* args)))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-divide (form)
|
2018-03-26 17:03:54 -07:00
|
|
|
|
(let ((args (cdr form)))
|
|
|
|
|
(if (and (cdr args)
|
|
|
|
|
(null (cdr (setq args (byte-opt--arith-reduce
|
|
|
|
|
#'/ (car args) (cdr args)))))
|
|
|
|
|
(numberp (car args)))
|
|
|
|
|
;; The entire argument list reduced to a constant; return it.
|
|
|
|
|
(car args)
|
|
|
|
|
;; Remove non-leading 1s, except for (/ x 1).
|
|
|
|
|
(when (memq 1 (cdr args))
|
|
|
|
|
(setq args (cons (car args) (or (remq 1 (cdr args)) (list 1)))))
|
|
|
|
|
(if (equal args (cdr form))
|
|
|
|
|
form
|
|
|
|
|
(cons '/ args)))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-binary-predicate (form)
|
2014-05-27 10:56:03 -04:00
|
|
|
|
(cond
|
|
|
|
|
((or (not (macroexp-const-p (nth 1 form)))
|
|
|
|
|
(nthcdr 3 form)) ;; In case there are more than 2 args.
|
|
|
|
|
form)
|
|
|
|
|
((macroexp-const-p (nth 2 form))
|
|
|
|
|
(condition-case ()
|
|
|
|
|
(list 'quote (eval form))
|
|
|
|
|
(error form)))
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(t ;; Moving the constant to the end can enable some lapcode optimizations.
|
2014-05-27 10:56:03 -04:00
|
|
|
|
(list (car form) (nth 2 form) (nth 1 form)))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2023-01-28 16:26:37 +01:00
|
|
|
|
(defun byte-opt--nary-comparison (form)
|
|
|
|
|
"Optimise n-ary comparisons such as `=', `<' etc."
|
|
|
|
|
(let ((nargs (length (cdr form))))
|
|
|
|
|
(cond
|
|
|
|
|
((= nargs 1)
|
|
|
|
|
`(progn (cadr form) t))
|
|
|
|
|
((>= nargs 3)
|
|
|
|
|
;; At least 3 arguments: transform to N-1 binary comparisons,
|
|
|
|
|
;; since those have their own byte-ops which are particularly
|
|
|
|
|
;; fast for fixnums.
|
|
|
|
|
(let* ((op (car form))
|
|
|
|
|
(bindings nil)
|
|
|
|
|
(rev-args nil))
|
|
|
|
|
(if (memq nil (mapcar #'macroexp-copyable-p (cddr form)))
|
|
|
|
|
;; At least one arg beyond the first is non-constant non-variable:
|
|
|
|
|
;; create temporaries for all args to guard against side-effects.
|
|
|
|
|
;; The optimiser will eliminate trivial bindings later.
|
|
|
|
|
(let ((i 1))
|
|
|
|
|
(dolist (arg (cdr form))
|
|
|
|
|
(let ((var (make-symbol (format "arg%d" i))))
|
|
|
|
|
(push var rev-args)
|
|
|
|
|
(push (list var arg) bindings)
|
|
|
|
|
(setq i (1+ i)))))
|
|
|
|
|
;; All args beyond the first are copyable: no temporary variables
|
|
|
|
|
;; required.
|
|
|
|
|
(setq rev-args (reverse (cdr form))))
|
|
|
|
|
(let ((prev (car rev-args))
|
|
|
|
|
(exprs nil))
|
|
|
|
|
(dolist (arg (cdr rev-args))
|
|
|
|
|
(push (list op arg prev) exprs)
|
|
|
|
|
(setq prev arg))
|
|
|
|
|
(let ((and-expr (cons 'and exprs)))
|
|
|
|
|
(if bindings
|
|
|
|
|
(list 'let (nreverse bindings) and-expr)
|
|
|
|
|
and-expr)))))
|
|
|
|
|
(t form))))
|
|
|
|
|
|
Simplify byte-code optimisation of pure functions
Most pure functions need no explicit optimisation; we can do away with
almost all uses of byte-optimize-predicate (now renamed to
byte-optimize-constant-args, since it is not just for predicates).
Also remove some superfluous arity warnings.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-identity, byte-optimize-memq)
(byte-optimize-nth, byte-optimize-nthcdr):
Remove arity warnings and simplify.
* lisp/emacs-lisp/byte-opt.el (<, >, <=, >=, not, null, consp, listp)
(symbolp, stringp, string<, string-lessp, proper-list-p, logand)
(logior, logxor, lognot, car, cdr, car-safe, cdr-safe):
Remove superfluous byte-optimizer property.
(byte-optimize-predicate): Rename to byte-optimize-constant-args.
All uses changed.
2020-07-06 17:38:52 +02:00
|
|
|
|
(defun byte-optimize-constant-args (form)
|
2023-02-08 13:18:32 +01:00
|
|
|
|
(let ((rest (cdr form)))
|
|
|
|
|
(while (and rest (macroexp-const-p (car rest)))
|
|
|
|
|
(setq rest (cdr rest)))
|
|
|
|
|
(if rest
|
|
|
|
|
form
|
|
|
|
|
(condition-case ()
|
|
|
|
|
(list 'quote (eval form t))
|
|
|
|
|
(error form)))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-identity (form)
|
|
|
|
|
(if (and (cdr form) (null (cdr (cdr form))))
|
|
|
|
|
(nth 1 form)
|
|
|
|
|
form))
|
|
|
|
|
|
2019-06-19 13:26:58 +02:00
|
|
|
|
(defun byte-optimize--constant-symbol-p (expr)
|
2023-02-08 13:18:32 +01:00
|
|
|
|
"Whether EXPR is a constant symbol, like (quote hello), nil, t, or :keyword."
|
|
|
|
|
(if (consp expr)
|
|
|
|
|
(and (memq (car expr) '(quote function))
|
|
|
|
|
(symbolp (cadr expr)))
|
|
|
|
|
(or (memq expr '(nil t))
|
|
|
|
|
(keywordp expr))))
|
|
|
|
|
|
|
|
|
|
(defsubst byteopt--eval-const (expr)
|
|
|
|
|
"Evaluate EXPR which must be a constant (quoted or self-evaluating).
|
|
|
|
|
Ie, (macroexp-const-p EXPR) must be true."
|
|
|
|
|
(if (consp expr)
|
|
|
|
|
(cadr expr) ; assumed to be 'VALUE or #'SYMBOL
|
|
|
|
|
expr))
|
2019-06-19 13:26:58 +02:00
|
|
|
|
|
2021-05-06 19:13:00 +02:00
|
|
|
|
(defun byte-optimize--fixnump (o)
|
|
|
|
|
"Return whether O is guaranteed to be a fixnum in all Emacsen.
|
|
|
|
|
See Info node `(elisp) Integer Basics'."
|
2022-07-21 12:18:59 +02:00
|
|
|
|
(and (integerp o) (<= -536870912 o 536870911)))
|
2021-05-06 19:13:00 +02:00
|
|
|
|
|
2019-06-19 13:26:58 +02:00
|
|
|
|
(defun byte-optimize-equal (form)
|
2021-05-06 19:13:00 +02:00
|
|
|
|
;; Replace `equal' or `eql' with `eq' if at least one arg is a
|
|
|
|
|
;; symbol or fixnum.
|
2019-06-19 13:26:58 +02:00
|
|
|
|
(byte-optimize-binary-predicate
|
|
|
|
|
(if (= (length (cdr form)) 2)
|
|
|
|
|
(if (or (byte-optimize--constant-symbol-p (nth 1 form))
|
2021-05-06 19:13:00 +02:00
|
|
|
|
(byte-optimize--constant-symbol-p (nth 2 form))
|
|
|
|
|
(byte-optimize--fixnump (nth 1 form))
|
|
|
|
|
(byte-optimize--fixnump (nth 2 form)))
|
2019-06-19 13:26:58 +02:00
|
|
|
|
(cons 'eq (cdr form))
|
|
|
|
|
form)
|
|
|
|
|
;; Arity errors reported elsewhere.
|
|
|
|
|
form)))
|
|
|
|
|
|
2021-07-20 15:46:32 +02:00
|
|
|
|
(defun byte-optimize-eq (form)
|
2021-07-20 19:32:11 +02:00
|
|
|
|
(pcase (cdr form)
|
|
|
|
|
((or `(,x nil) `(nil ,x)) `(not ,x))
|
|
|
|
|
(_ (byte-optimize-binary-predicate form))))
|
2021-07-20 15:46:32 +02:00
|
|
|
|
|
2019-06-19 13:26:58 +02:00
|
|
|
|
(defun byte-optimize-member (form)
|
2021-07-28 21:07:58 +02:00
|
|
|
|
(cond
|
|
|
|
|
((/= (length (cdr form)) 2) form) ; arity error
|
|
|
|
|
((null (nth 2 form)) ; empty list
|
|
|
|
|
`(progn ,(nth 1 form) nil))
|
|
|
|
|
;; Replace `member' or `memql' with `memq' if the first arg is a symbol
|
|
|
|
|
;; or fixnum, or the second arg is a list of symbols or fixnums.
|
|
|
|
|
((or (byte-optimize--constant-symbol-p (nth 1 form))
|
|
|
|
|
(byte-optimize--fixnump (nth 1 form))
|
|
|
|
|
(let ((arg2 (nth 2 form)))
|
|
|
|
|
(and (macroexp-const-p arg2)
|
2023-02-08 13:18:32 +01:00
|
|
|
|
(let ((listval (byteopt--eval-const arg2)))
|
2021-07-28 21:07:58 +02:00
|
|
|
|
(and (listp listval)
|
|
|
|
|
(not (memq nil (mapcar
|
|
|
|
|
(lambda (o)
|
|
|
|
|
(or (symbolp o)
|
|
|
|
|
(byte-optimize--fixnump o)))
|
|
|
|
|
listval))))))))
|
|
|
|
|
(cons 'memq (cdr form)))
|
|
|
|
|
(t form)))
|
2019-06-19 13:26:58 +02:00
|
|
|
|
|
2020-07-06 12:51:04 +02:00
|
|
|
|
(defun byte-optimize-assoc (form)
|
|
|
|
|
;; Replace 2-argument `assoc' with `assq', `rassoc' with `rassq',
|
2021-05-06 19:13:00 +02:00
|
|
|
|
;; if the first arg is a symbol or fixnum.
|
2020-10-31 14:16:25 +01:00
|
|
|
|
(cond
|
|
|
|
|
((/= (length form) 3)
|
|
|
|
|
form)
|
2021-07-28 21:07:58 +02:00
|
|
|
|
((null (nth 2 form)) ; empty list
|
|
|
|
|
`(progn ,(nth 1 form) nil))
|
2021-05-06 19:13:00 +02:00
|
|
|
|
((or (byte-optimize--constant-symbol-p (nth 1 form))
|
|
|
|
|
(byte-optimize--fixnump (nth 1 form)))
|
2020-10-31 14:16:25 +01:00
|
|
|
|
(cons (if (eq (car form) 'assoc) 'assq 'rassq)
|
|
|
|
|
(cdr form)))
|
|
|
|
|
(t (byte-optimize-constant-args form))))
|
2020-07-06 12:51:04 +02:00
|
|
|
|
|
2021-07-28 21:07:58 +02:00
|
|
|
|
(defun byte-optimize-assq (form)
|
|
|
|
|
(cond
|
|
|
|
|
((/= (length form) 3)
|
|
|
|
|
form)
|
|
|
|
|
((null (nth 2 form)) ; empty list
|
|
|
|
|
`(progn ,(nth 1 form) nil))
|
|
|
|
|
(t (byte-optimize-constant-args form))))
|
|
|
|
|
|
2018-03-25 00:38:01 +05:30
|
|
|
|
(defun byte-optimize-memq (form)
|
Simplify byte-code optimisation of pure functions
Most pure functions need no explicit optimisation; we can do away with
almost all uses of byte-optimize-predicate (now renamed to
byte-optimize-constant-args, since it is not just for predicates).
Also remove some superfluous arity warnings.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-identity, byte-optimize-memq)
(byte-optimize-nth, byte-optimize-nthcdr):
Remove arity warnings and simplify.
* lisp/emacs-lisp/byte-opt.el (<, >, <=, >=, not, null, consp, listp)
(symbolp, stringp, string<, string-lessp, proper-list-p, logand)
(logior, logxor, lognot, car, cdr, car-safe, cdr-safe):
Remove superfluous byte-optimizer property.
(byte-optimize-predicate): Rename to byte-optimize-constant-args.
All uses changed.
2020-07-06 17:38:52 +02:00
|
|
|
|
(if (= (length (cdr form)) 2)
|
|
|
|
|
(let ((list (nth 2 form)))
|
2021-07-28 21:07:58 +02:00
|
|
|
|
(cond
|
|
|
|
|
((null list) ; empty list
|
|
|
|
|
`(progn ,(nth 1 form) nil))
|
|
|
|
|
;; (memq foo '(bar)) => (and (eq foo 'bar) '(bar))
|
|
|
|
|
((and (eq (car-safe list) 'quote)
|
|
|
|
|
(listp (setq list (cadr list)))
|
|
|
|
|
(= (length list) 1))
|
|
|
|
|
`(and (eq ,(nth 1 form) ',(nth 0 list))
|
|
|
|
|
',list))
|
|
|
|
|
(t form)))
|
Simplify byte-code optimisation of pure functions
Most pure functions need no explicit optimisation; we can do away with
almost all uses of byte-optimize-predicate (now renamed to
byte-optimize-constant-args, since it is not just for predicates).
Also remove some superfluous arity warnings.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-identity, byte-optimize-memq)
(byte-optimize-nth, byte-optimize-nthcdr):
Remove arity warnings and simplify.
* lisp/emacs-lisp/byte-opt.el (<, >, <=, >=, not, null, consp, listp)
(symbolp, stringp, string<, string-lessp, proper-list-p, logand)
(logior, logxor, lognot, car, cdr, car-safe, cdr-safe):
Remove superfluous byte-optimizer property.
(byte-optimize-predicate): Rename to byte-optimize-constant-args.
All uses changed.
2020-07-06 17:38:52 +02:00
|
|
|
|
;; Arity errors reported elsewhere.
|
|
|
|
|
form))
|
2018-03-25 00:38:01 +05:30
|
|
|
|
|
2019-06-16 13:13:47 +02:00
|
|
|
|
(defun byte-optimize-concat (form)
|
2023-02-08 13:45:57 +01:00
|
|
|
|
"Merge adjacent constant arguments to `concat' and flatten nested forms."
|
2019-06-16 13:13:47 +02:00
|
|
|
|
(let ((args (cdr form))
|
|
|
|
|
(newargs nil))
|
|
|
|
|
(while args
|
2023-02-08 13:45:57 +01:00
|
|
|
|
(let ((strings nil))
|
|
|
|
|
(while
|
|
|
|
|
(and args
|
|
|
|
|
(let ((arg (car args)))
|
|
|
|
|
(pcase arg
|
|
|
|
|
;; Merge consecutive constant arguments.
|
|
|
|
|
((pred macroexp-const-p)
|
|
|
|
|
(let ((val (byteopt--eval-const arg)))
|
|
|
|
|
(and (or (stringp val)
|
|
|
|
|
(and (or (listp val) (vectorp val))
|
|
|
|
|
(not (memq nil
|
|
|
|
|
(mapcar #'characterp val)))))
|
|
|
|
|
(progn
|
|
|
|
|
(push val strings)
|
|
|
|
|
(setq args (cdr args))
|
|
|
|
|
t))))
|
|
|
|
|
;; Flatten nested `concat' form.
|
|
|
|
|
(`(concat . ,nested-args)
|
|
|
|
|
(setq args (append nested-args (cdr args)))
|
|
|
|
|
t)))))
|
|
|
|
|
|
2019-06-16 13:13:47 +02:00
|
|
|
|
(when strings
|
|
|
|
|
(let ((s (apply #'concat (nreverse strings))))
|
|
|
|
|
(when (not (zerop (length s)))
|
|
|
|
|
(push s newargs)))))
|
|
|
|
|
(when args
|
|
|
|
|
(push (car args) newargs)
|
|
|
|
|
(setq args (cdr args))))
|
|
|
|
|
(if (= (length newargs) (length (cdr form)))
|
|
|
|
|
form ; No improvement.
|
|
|
|
|
(cons 'concat (nreverse newargs)))))
|
|
|
|
|
|
2022-03-16 16:24:24 +01:00
|
|
|
|
(defun byte-optimize-string-greaterp (form)
|
|
|
|
|
;; Rewrite in terms of `string-lessp' which has its own bytecode.
|
|
|
|
|
(pcase (cdr form)
|
|
|
|
|
(`(,a ,b) (let ((arg1 (make-symbol "arg1")))
|
|
|
|
|
`(let ((,arg1 ,a))
|
|
|
|
|
(string-lessp ,b ,arg1))))
|
|
|
|
|
(_ form)))
|
|
|
|
|
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'identity 'byte-optimizer #'byte-optimize-identity)
|
|
|
|
|
(put 'memq 'byte-optimizer #'byte-optimize-memq)
|
|
|
|
|
(put 'memql 'byte-optimizer #'byte-optimize-member)
|
|
|
|
|
(put 'member 'byte-optimizer #'byte-optimize-member)
|
|
|
|
|
(put 'assoc 'byte-optimizer #'byte-optimize-assoc)
|
|
|
|
|
(put 'rassoc 'byte-optimizer #'byte-optimize-assoc)
|
2021-07-28 21:07:58 +02:00
|
|
|
|
(put 'assq 'byte-optimizer #'byte-optimize-assq)
|
|
|
|
|
(put 'rassq 'byte-optimizer #'byte-optimize-assq)
|
2020-07-31 11:58:13 -04:00
|
|
|
|
|
|
|
|
|
(put '+ 'byte-optimizer #'byte-optimize-plus)
|
|
|
|
|
(put '* 'byte-optimizer #'byte-optimize-multiply)
|
|
|
|
|
(put '- 'byte-optimizer #'byte-optimize-minus)
|
|
|
|
|
(put '/ 'byte-optimizer #'byte-optimize-divide)
|
2020-08-03 16:29:06 +02:00
|
|
|
|
(put 'max 'byte-optimizer #'byte-optimize-min-max)
|
|
|
|
|
(put 'min 'byte-optimizer #'byte-optimize-min-max)
|
2020-07-31 11:58:13 -04:00
|
|
|
|
|
2021-07-20 15:46:32 +02:00
|
|
|
|
(put 'eq 'byte-optimizer #'byte-optimize-eq)
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'eql 'byte-optimizer #'byte-optimize-equal)
|
|
|
|
|
(put 'equal 'byte-optimizer #'byte-optimize-equal)
|
|
|
|
|
(put 'string= 'byte-optimizer #'byte-optimize-binary-predicate)
|
|
|
|
|
(put 'string-equal 'byte-optimizer #'byte-optimize-binary-predicate)
|
|
|
|
|
|
2023-01-28 16:26:37 +01:00
|
|
|
|
(put '= 'byte-optimizer #'byte-opt--nary-comparison)
|
|
|
|
|
(put '< 'byte-optimizer #'byte-opt--nary-comparison)
|
|
|
|
|
(put '<= 'byte-optimizer #'byte-opt--nary-comparison)
|
|
|
|
|
(put '> 'byte-optimizer #'byte-opt--nary-comparison)
|
|
|
|
|
(put '>= 'byte-optimizer #'byte-opt--nary-comparison)
|
|
|
|
|
|
2022-03-16 16:24:24 +01:00
|
|
|
|
(put 'string-greaterp 'byte-optimizer #'byte-optimize-string-greaterp)
|
|
|
|
|
(put 'string> 'byte-optimizer #'byte-optimize-string-greaterp)
|
|
|
|
|
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'concat 'byte-optimizer #'byte-optimize-concat)
|
2019-06-16 13:13:47 +02:00
|
|
|
|
|
2003-02-04 13:24:35 +00:00
|
|
|
|
;; I'm not convinced that this is necessary. Doesn't the optimizer loop
|
1992-07-10 22:06:47 +00:00
|
|
|
|
;; take care of this? - Jamie
|
|
|
|
|
;; I think this may some times be necessary to reduce ie (quote 5) to 5,
|
1993-06-09 11:59:12 +00:00
|
|
|
|
;; so arithmetic optimizers recognize the numeric constant. - Hallvard
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'quote 'byte-optimizer #'byte-optimize-quote)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-optimize-quote (form)
|
|
|
|
|
(if (or (consp (nth 1 form))
|
|
|
|
|
(and (symbolp (nth 1 form))
|
2021-07-21 10:54:43 +02:00
|
|
|
|
(not (macroexp--const-symbol-p (nth 1 form)))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
form
|
|
|
|
|
(nth 1 form)))
|
|
|
|
|
|
|
|
|
|
(defun byte-optimize-and (form)
|
2022-08-12 20:12:54 +02:00
|
|
|
|
(let ((seq nil)
|
|
|
|
|
(new-args nil)
|
|
|
|
|
(nil-result nil)
|
|
|
|
|
(args (cdr form)))
|
|
|
|
|
(while
|
|
|
|
|
(and args
|
|
|
|
|
(let ((arg (car args)))
|
|
|
|
|
(cond
|
|
|
|
|
(seq ; previous arg was always-true
|
|
|
|
|
(push arg seq)
|
|
|
|
|
(unless (and (cdr args) (byte-compile-trueconstp arg))
|
|
|
|
|
(push `(progn . ,(nreverse seq)) new-args)
|
|
|
|
|
(setq seq nil))
|
|
|
|
|
t)
|
|
|
|
|
((and (cdr args) (byte-compile-trueconstp arg))
|
|
|
|
|
;; Always-true arg: evaluate unconditionally.
|
|
|
|
|
(push arg seq)
|
|
|
|
|
t)
|
|
|
|
|
((and arg (not (byte-compile-nilconstp arg)))
|
|
|
|
|
(push arg new-args)
|
|
|
|
|
t)
|
|
|
|
|
(t
|
|
|
|
|
;; Throw away the remaining args; this one is always false.
|
|
|
|
|
(setq nil-result t)
|
|
|
|
|
(when arg
|
|
|
|
|
(push arg new-args)) ; keep possible side-effects
|
|
|
|
|
nil))))
|
|
|
|
|
(setq args (cdr args)))
|
|
|
|
|
|
|
|
|
|
(setq new-args (nreverse new-args))
|
|
|
|
|
(if (equal new-args (cdr form))
|
|
|
|
|
;; Input is unchanged: keep original form, and don't represent
|
|
|
|
|
;; a nil result explicitly because that would lead to infinite
|
2022-09-29 15:19:01 +02:00
|
|
|
|
;; growth when the optimizer is iterated.
|
2022-08-12 20:12:54 +02:00
|
|
|
|
(setq nil-result nil)
|
|
|
|
|
(setq form (cons (car form) new-args)))
|
|
|
|
|
|
|
|
|
|
(let ((new-form
|
|
|
|
|
(pcase form
|
|
|
|
|
;; (and (progn ... X) ...) -> (progn ... (and X ...))
|
|
|
|
|
(`(,head (progn . ,forms) . ,rest)
|
|
|
|
|
`(progn ,@(butlast forms) (,head ,(car (last forms)) . ,rest)))
|
|
|
|
|
(`(,_) t) ; (and) -> t
|
|
|
|
|
(`(,_ ,arg) arg) ; (and X) -> X
|
|
|
|
|
(_ (byte-optimize-constant-args form)))))
|
|
|
|
|
(if nil-result
|
|
|
|
|
`(progn ,new-form nil)
|
|
|
|
|
new-form))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-or (form)
|
2022-08-12 20:12:54 +02:00
|
|
|
|
(let ((seq nil)
|
|
|
|
|
(new-args nil)
|
|
|
|
|
(args (remq nil (cdr form)))) ; Discard nil arguments.
|
|
|
|
|
(while
|
|
|
|
|
(and args
|
|
|
|
|
(let ((arg (car args)))
|
|
|
|
|
(cond
|
|
|
|
|
(seq ; previous arg was always-false
|
|
|
|
|
(push arg seq)
|
|
|
|
|
(unless (and (cdr args) (byte-compile-nilconstp arg))
|
|
|
|
|
(push `(progn . ,(nreverse seq)) new-args)
|
|
|
|
|
(setq seq nil))
|
|
|
|
|
t)
|
|
|
|
|
((and (cdr args) (byte-compile-nilconstp arg))
|
|
|
|
|
;; Always-false arg: evaluate unconditionally.
|
|
|
|
|
(push arg seq)
|
|
|
|
|
t)
|
|
|
|
|
(t
|
|
|
|
|
(push arg new-args)
|
|
|
|
|
;; If this arg is always true, throw away the remaining args.
|
|
|
|
|
(not (byte-compile-trueconstp arg))))))
|
|
|
|
|
(setq args (cdr args)))
|
|
|
|
|
|
|
|
|
|
(setq new-args (nreverse new-args))
|
|
|
|
|
;; Keep original form unless the arguments changed.
|
|
|
|
|
(unless (equal new-args (cdr form))
|
|
|
|
|
(setq form (cons (car form) new-args)))
|
|
|
|
|
|
|
|
|
|
(pcase form
|
|
|
|
|
;; (or (progn ... X) ...) -> (progn ... (or X ...))
|
|
|
|
|
(`(,head (progn . ,forms) . ,rest)
|
|
|
|
|
`(progn ,@(butlast forms) (,head ,(car (last forms)) . ,rest)))
|
|
|
|
|
(`(,_) nil) ; (or) -> nil
|
|
|
|
|
(`(,_ ,arg) arg) ; (or X) -> X
|
|
|
|
|
(_ (byte-optimize-constant-args form)))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-cond (form)
|
|
|
|
|
;; if any clauses have a literal nil as their test, throw them away.
|
|
|
|
|
;; if any clause has a literal non-nil constant as its test, throw
|
|
|
|
|
;; away all following clauses.
|
|
|
|
|
(let (rest)
|
|
|
|
|
;; This must be first, to reduce (cond (t ...) (nil)) to (progn t ...)
|
|
|
|
|
(while (setq rest (assq nil (cdr form)))
|
2018-03-26 17:03:54 -07:00
|
|
|
|
(setq form (remq rest form)))
|
|
|
|
|
(setq form (remq nil form))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(setq rest form)
|
|
|
|
|
(while (setq rest (cdr rest))
|
|
|
|
|
(cond ((byte-compile-trueconstp (car-safe (car rest)))
|
2007-11-13 16:10:14 +00:00
|
|
|
|
;; This branch will always be taken: kill the subsequent ones.
|
|
|
|
|
(cond ((eq rest (cdr form)) ;First branch of `cond'.
|
|
|
|
|
(setq form `(progn ,@(car rest))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
((cdr rest)
|
|
|
|
|
(setq form (copy-sequence form))
|
|
|
|
|
(setcdr (memq (car rest) form) nil)))
|
2007-11-13 16:10:14 +00:00
|
|
|
|
(setq rest nil))
|
|
|
|
|
((and (consp (car rest))
|
|
|
|
|
(byte-compile-nilconstp (caar rest)))
|
|
|
|
|
;; This branch will never be taken: kill its body.
|
|
|
|
|
(setcdr (car rest) nil)))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
;;
|
|
|
|
|
;; Turn (cond (( <x> )) ... ) into (or <x> (cond ... ))
|
|
|
|
|
(if (eq 'cond (car-safe form))
|
|
|
|
|
(let ((clauses (cdr form)))
|
|
|
|
|
(if (and (consp (car clauses))
|
|
|
|
|
(null (cdr (car clauses))))
|
|
|
|
|
(list 'or (car (car clauses))
|
|
|
|
|
(byte-optimize-cond
|
|
|
|
|
(cons (car form) (cdr (cdr form)))))
|
2021-11-02 14:48:55 +01:00
|
|
|
|
(and clauses form)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
form))
|
|
|
|
|
|
2022-08-12 20:12:25 +02:00
|
|
|
|
(defsubst byte-opt--negate (form)
|
|
|
|
|
"Negate FORM, avoiding double negation if already negated."
|
|
|
|
|
(if (and (consp form) (memq (car form) '(not null)))
|
|
|
|
|
(cadr form)
|
|
|
|
|
`(not ,form)))
|
|
|
|
|
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-optimize-if (form)
|
2022-08-12 20:12:25 +02:00
|
|
|
|
(let ((condition (nth 1 form))
|
|
|
|
|
(then (nth 2 form))
|
|
|
|
|
(else (nthcdr 3 form)))
|
|
|
|
|
(cond
|
|
|
|
|
;; (if (progn ... X) ...) -> (progn ... (if X ...))
|
|
|
|
|
((eq (car-safe condition) 'progn)
|
|
|
|
|
(nconc (butlast condition)
|
|
|
|
|
(list
|
|
|
|
|
(byte-optimize-if
|
|
|
|
|
`(,(car form) ,(car (last condition)) ,@(nthcdr 2 form))))))
|
|
|
|
|
;; (if TRUE THEN ...) -> (progn TRUE THEN)
|
|
|
|
|
((byte-compile-trueconstp condition)
|
|
|
|
|
`(progn ,condition ,then))
|
|
|
|
|
;; (if FALSE THEN ELSE...) -> (progn FALSE ELSE...)
|
|
|
|
|
((byte-compile-nilconstp condition)
|
|
|
|
|
(if else
|
|
|
|
|
`(progn ,condition ,@else)
|
|
|
|
|
condition))
|
2022-12-16 15:56:04 +01:00
|
|
|
|
;; (if X t) -> (not (not X))
|
|
|
|
|
((and (eq then t) (null else))
|
2022-08-12 20:12:25 +02:00
|
|
|
|
`(not ,(byte-opt--negate condition)))
|
|
|
|
|
;; (if VAR VAR X...) -> (or VAR (progn X...))
|
|
|
|
|
((and (symbolp condition) (eq condition then))
|
|
|
|
|
`(or ,then ,(if (cdr else)
|
|
|
|
|
`(progn . ,else)
|
|
|
|
|
(car else))))
|
|
|
|
|
;; (if X THEN nil) -> (if X THEN)
|
|
|
|
|
(then
|
|
|
|
|
(if (equal else '(nil))
|
|
|
|
|
(list (car form) condition then)
|
|
|
|
|
form))
|
|
|
|
|
;; (if X nil ELSE...) -> (if (not X) (progn ELSE...))
|
|
|
|
|
((or (car else) (cdr else))
|
|
|
|
|
(list (car form) (byte-opt--negate condition)
|
|
|
|
|
(if (cdr else)
|
|
|
|
|
`(progn . ,else)
|
|
|
|
|
(car else))))
|
|
|
|
|
;; (if X nil nil) -> (progn X nil)
|
|
|
|
|
(t
|
|
|
|
|
(list 'progn condition nil)))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-while (form)
|
2022-08-12 20:12:25 +02:00
|
|
|
|
(let ((condition (nth 1 form)))
|
|
|
|
|
(if (byte-compile-nilconstp condition)
|
|
|
|
|
condition
|
|
|
|
|
form)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2022-08-16 19:03:46 +02:00
|
|
|
|
(defun byte-optimize-not (form)
|
|
|
|
|
(and (= (length form) 2)
|
|
|
|
|
(let ((arg (nth 1 form)))
|
|
|
|
|
(cond ((null arg) t)
|
|
|
|
|
((macroexp-const-p arg) nil)
|
|
|
|
|
((byte-compile-nilconstp arg) `(progn ,arg t))
|
|
|
|
|
((byte-compile-trueconstp arg) `(progn ,arg nil))
|
|
|
|
|
(t form)))))
|
|
|
|
|
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'and 'byte-optimizer #'byte-optimize-and)
|
|
|
|
|
(put 'or 'byte-optimizer #'byte-optimize-or)
|
|
|
|
|
(put 'cond 'byte-optimizer #'byte-optimize-cond)
|
|
|
|
|
(put 'if 'byte-optimizer #'byte-optimize-if)
|
|
|
|
|
(put 'while 'byte-optimizer #'byte-optimize-while)
|
2022-08-16 19:03:46 +02:00
|
|
|
|
(put 'not 'byte-optimizer #'byte-optimize-not)
|
|
|
|
|
(put 'null 'byte-optimizer #'byte-optimize-not)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
;; byte-compile-negation-optimizer lives in bytecomp.el
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put '/= 'byte-optimizer #'byte-compile-negation-optimizer)
|
|
|
|
|
(put 'atom 'byte-optimizer #'byte-compile-negation-optimizer)
|
|
|
|
|
(put 'nlistp 'byte-optimizer #'byte-compile-negation-optimizer)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(defun byte-optimize-funcall (form)
|
2000-06-12 05:06:37 +00:00
|
|
|
|
;; (funcall (lambda ...) ...) ==> ((lambda ...) ...)
|
|
|
|
|
;; (funcall foo ...) ==> (foo ...)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(let ((fn (nth 1 form)))
|
|
|
|
|
(if (memq (car-safe fn) '(quote function))
|
|
|
|
|
(cons (nth 1 fn) (cdr (cdr form)))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
form)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defun byte-optimize-apply (form)
|
2022-08-12 15:04:51 +02:00
|
|
|
|
(let ((len (length form)))
|
|
|
|
|
(if (>= len 2)
|
|
|
|
|
(let ((fn (nth 1 form))
|
|
|
|
|
(last (nth (1- len) form)))
|
|
|
|
|
(cond
|
|
|
|
|
;; (apply F ... '(X Y ...)) -> (funcall F ... 'X 'Y ...)
|
|
|
|
|
((or (null last)
|
|
|
|
|
(eq (car-safe last) 'quote))
|
|
|
|
|
(let ((last-value (nth 1 last)))
|
|
|
|
|
(if (listp last-value)
|
|
|
|
|
`(funcall ,fn ,@(butlast (cddr form))
|
|
|
|
|
,@(mapcar (lambda (x) (list 'quote x)) last-value))
|
First commit of scratch/correct-warning-pos.
This branch is intended to generate correct position information in warning
and error messages from the byte compiler, and is intended thereby to fix bugs
It introduces a new mechanism, the symbol with position. This is taken over
from the previous git branch scratch/accurate-warning-pos which was abandoned
for being too slow. The main difference in the current branch is that the
symbol `nil' is never given a position, thus speeding up NILP markedly.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-optimize-form-code-walker, byte-optimize-let-form, byte-optimize-while)
(byte-optimize-apply): Use byte-compile-warn-x in place of byte-compile-warn.
* lisp/emacs-lisp/bytecomp.el (byte-compile--form-stack): New variable.
(byte-compile-strip-s-p-1, byte-compile-strip-symbol-positions): New
functions.
(byte-compile-recurse-toplevel, byte-compile-initial-macro-environment)
(byte-compile-preprocess, byte-compile-macroexpand-declare-function): Bind
print-symbols-bare to non-nil.
(byte-compile--first-symbol, byte-compile--warning-source-offset): New
functions.
(byte-compile-warning-prefix): Modify to output two sets of position
information, the old (incorrect) set and the new set.
(byte-compile-warn): Strip positions from symbols before outputting.
(byte-compile-warn-x): New function which outputs a correct position supplied
in an argument.
(byte-compile-warn-obsolete, byte-compile-emit-callargs-warn)
(byte-compile-format-warn, byte-compile-nogroup-warn)
(byte-compile-arglist-warn, byte-compile-docstring-length-warn)
(byte-compile-warn-about-unresolved-functions, byte-compile-file)
(byte-compile--check-prefixed-var, byte-compile--declare-var)
(byte-compile-file-form-defvar-function, byte-compile-file-form-defmumble)
(byte-compile-check-lambda-list, byte-compile--warn-lexical-dynamic)
(byte-compile-lambda, byte-compile-form, byte-compile-normal-call)
(byte-compile-check-variable, byte-compile-free-vars-warn)
(byte-compile-subr-wrong-args, byte-compile-fset, byte-compile-set-default)
(byte-compile-condition-case, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-make-variable-buffer-local, byte-compile-define-symbol-prop)
(byte-compile-define-keymap): Replace byte-compile-warn with
byte-compile-warn-x.
(byte-compile-file, compile-defun): Bind symbols-with-pos-enabled to non-nil.
(compile-defun, byte-compile-from-buffer): Use `read-positioning-symbols'
rather than plain `read'.
(byte-compile-toplevel-file-form, byte-compile-form): Dynamically bind
byte-compile--form-stack.
(byte-compile-file-form-autoload, byte-compile-file-form-defvar)
(byte-compile-file-form-make-obsolete, byte-compile-lambda)
(byte-compile-push-constant, byte-compile-cond-jump-table)
(byte-compile-define-keymap, byte-compile-annotate-call-tree):
Strip positions from symbols where they are unwanted.
(byte-compile-file-form-defvar): Strip positions from symbols using
`bare-symbol'.
(byte-compile-file-form-defmumble): New variable bare-name, a version of name
without its position.
(byte-compile-lambda): Similarly, new variable bare-arglist.
(byte-compile-free-vars-warn): New argument arg supplying position information
to byte-compile-warn-x.
(byte-compile-push-constant): Manipulation of symbol positions.
(display-call-tree): Strip positions from symbols.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use)
(cconv--analyze-function, cconv-analyze-form): Replace use of
byte-compile-warn with byte-compile-warn-x.
* lisp/emacs-lisp/cl-generic.el (cl-defmethod): New variable org-name which
will supply position information to a new macroexp-warn-and-return.
* lisp/emacs-lisp/cl-macs.el (cl-macs--strip-s-p-1)
(cl-macs--strip-symbol-positions): New functions to strip positions from
symbols in an expression. These duplicaate similarly named functions in
bytecomp.el.
* lisp/emacs-lisp/macroexpand.el (macroexp--warn-wrap): Calls
byte-compile-warn-x in place of byte-compile-warn.
(macroexp-warn-and-return): Commented out new position parameter _arg.
* src/.gdbinit: Add in code to handle symbols with position.
* src/alloc.c (XPNTR, set_symbol_name, valid_lisp_object_p, purecopy)
(mark_char_table, mark_object, survives_gc_p, symbol_uses_obj): Use
BARE_SYMBOL_P and XBARE_SYMBOL in place of the former SYMBOLP and XSYMBOL.
(build_symbol_with_pos): New function.
(Fgarbage_collect): Bind Qsymbols_with_pos_enabled to nil around the call to
garbage_collect.
* src/data.c (Ftype_of): Add case for PVEC_SYMBOL_WITH_POS.
(Fbare_symbol_p, Fsymbol_with_pos_p, Fbare_symbol, Fsymbol_with_pos_pos)
(Fposition_symbol): New functions.
(symbols_with_pos_enabled): New boolean variable.
* src/fns.c (internal_equal, hash_lookup): Handle symbols with position.
* src/keyboard.c (recursive_edit_1): Bind Qsymbols_with_pos_enabled and
Qprint_symbols_bare to nil.
* src/lisp.h (lisp_h_PSEUDOVECTORP): New macro.
(lisp_h_BASE_EQ): New name for the former lisp_h_EQ.
(lisp_h_EQ): Extended to handle symbols with position.
(lisp_h_NILP): Now uses BASE_EQ rather than EQ.
(lisp_h_SYMBOL_WITH_POS_P, lisp_h_BARE_SYMBOL_P): New macros.
(lisp_h_SYMBOLP): Redefined to handle symbols with position.
(BARE_SYMBOL_P, BASE_EQ): New macros.
(SYMBOLP (macro)): Removed.
(SYMBOLP (function), XSYMBOL, make_lisp_symbol, builtin_lisp_symbol)
(c_symbol_p): Moved to later in file.
(struct Lisp_Symbol_With_Pos): New data type.
(pvec_type): PVEC_SYMBOL_WITH_POS: New type code.
(PSEUDOVECTORP): Redefined to use the lisp_h_PSEUDOVECTORP.
(BARE_SYMBOL_P, SYMBOL_WITH_POS_P, SYMBOLP, XSYMBOL_WITH_POS, XBARE_SYMBOL)
(XSYMBOL, make_lisp_symbol, builtin_lisp_symbol, c_symbol_p, CHECK_SYMBOL)
(BASE_EQ): New functions, or functions moved from earlier in the file.
(SYMBOL_WITH_POS_SYM, SYMBOL_WITH_POS_POS): New INLINE functions.
* src/lread.c (read0, read1, read_list, read_vector, read_internal_start)
(list2): Add a new bool parameter locate_syms.
(Fread_positioning_symbols): New function.
(Fread_from_string, read_internal_start, read0, read1, read_list): Pass around
suitable values for locate_syms.
(read1): Build symbols with position when locate_syms is true.
* src/print.c (print_vectorlike): Add handling for PVEC_SYMBOL_WITH_POS.
(print_object): Replace EQ with BASE_EQ.
(print_symbols_bare): New boolean variable.
2021-11-29 11:19:31 +00:00
|
|
|
|
(byte-compile-warn-x
|
2022-08-12 15:04:51 +02:00
|
|
|
|
last "last arg to apply can't be a literal atom: `%s'" last)
|
|
|
|
|
nil)))
|
|
|
|
|
;; (apply F ... (list X Y ...)) -> (funcall F ... X Y ...)
|
|
|
|
|
((eq (car-safe last) 'list)
|
|
|
|
|
`(funcall ,fn ,@(butlast (cddr form)) ,@(cdr last)))
|
2023-01-12 14:07:45 +01:00
|
|
|
|
;; (apply F ... (cons X Y)) -> (apply F ... X Y)
|
|
|
|
|
((eq (car-safe last) 'cons)
|
|
|
|
|
(append (butlast form) (cdr last)))
|
2022-08-12 15:04:51 +02:00
|
|
|
|
(t form)))
|
|
|
|
|
form)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'funcall 'byte-optimizer #'byte-optimize-funcall)
|
|
|
|
|
(put 'apply 'byte-optimizer #'byte-optimize-apply)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'let 'byte-optimizer #'byte-optimize-letX)
|
|
|
|
|
(put 'let* 'byte-optimizer #'byte-optimize-letX)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-optimize-letX (form)
|
2021-07-29 15:35:55 +02:00
|
|
|
|
(pcase form
|
|
|
|
|
;; No bindings.
|
|
|
|
|
(`(,_ () . ,body)
|
|
|
|
|
`(progn . ,body))
|
|
|
|
|
|
|
|
|
|
;; Body is empty or just contains a constant.
|
|
|
|
|
(`(,head ,bindings . ,(or '() `(,(and const (pred macroexp-const-p)))))
|
|
|
|
|
(if (eq head 'let)
|
2022-06-06 11:10:05 +02:00
|
|
|
|
`(progn ,@(mapcar #'cadr bindings) ,const)
|
|
|
|
|
`(,head ,(butlast bindings) ,(cadar (last bindings)) ,const)))
|
2021-07-29 15:35:55 +02:00
|
|
|
|
|
|
|
|
|
;; Body is last variable.
|
2021-09-25 12:15:21 +02:00
|
|
|
|
(`(,head ,(and bindings
|
2022-06-06 11:10:05 +02:00
|
|
|
|
(let last-var (caar (last bindings))))
|
2021-09-25 12:15:21 +02:00
|
|
|
|
,(and last-var ; non-linear pattern
|
|
|
|
|
(pred symbolp) (pred (not keywordp)) (pred (not booleanp))))
|
2021-07-29 15:35:55 +02:00
|
|
|
|
(if (eq head 'let)
|
2022-06-06 11:10:05 +02:00
|
|
|
|
`(progn ,@(mapcar #'cadr bindings))
|
|
|
|
|
`(,head ,(butlast bindings) ,(cadar (last bindings)))))
|
2021-07-29 15:35:55 +02:00
|
|
|
|
|
|
|
|
|
(_ form)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'nth 'byte-optimizer #'byte-optimize-nth)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-optimize-nth (form)
|
2003-01-05 00:28:18 +00:00
|
|
|
|
(if (= (safe-length form) 3)
|
|
|
|
|
(if (memq (nth 1 form) '(0 1))
|
|
|
|
|
(list 'car (if (zerop (nth 1 form))
|
|
|
|
|
(nth 2 form)
|
|
|
|
|
(list 'cdr (nth 2 form))))
|
Simplify byte-code optimisation of pure functions
Most pure functions need no explicit optimisation; we can do away with
almost all uses of byte-optimize-predicate (now renamed to
byte-optimize-constant-args, since it is not just for predicates).
Also remove some superfluous arity warnings.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-identity, byte-optimize-memq)
(byte-optimize-nth, byte-optimize-nthcdr):
Remove arity warnings and simplify.
* lisp/emacs-lisp/byte-opt.el (<, >, <=, >=, not, null, consp, listp)
(symbolp, stringp, string<, string-lessp, proper-list-p, logand)
(logior, logxor, lognot, car, cdr, car-safe, cdr-safe):
Remove superfluous byte-optimizer property.
(byte-optimize-predicate): Rename to byte-optimize-constant-args.
All uses changed.
2020-07-06 17:38:52 +02:00
|
|
|
|
form)
|
2003-01-05 00:28:18 +00:00
|
|
|
|
form))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'nthcdr 'byte-optimizer #'byte-optimize-nthcdr)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-optimize-nthcdr (form)
|
2003-01-05 00:28:18 +00:00
|
|
|
|
(if (= (safe-length form) 3)
|
|
|
|
|
(if (memq (nth 1 form) '(0 1 2))
|
|
|
|
|
(let ((count (nth 1 form)))
|
|
|
|
|
(setq form (nth 2 form))
|
|
|
|
|
(while (>= (setq count (1- count)) 0)
|
|
|
|
|
(setq form (list 'cdr form)))
|
|
|
|
|
form)
|
Simplify byte-code optimisation of pure functions
Most pure functions need no explicit optimisation; we can do away with
almost all uses of byte-optimize-predicate (now renamed to
byte-optimize-constant-args, since it is not just for predicates).
Also remove some superfluous arity warnings.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-identity, byte-optimize-memq)
(byte-optimize-nth, byte-optimize-nthcdr):
Remove arity warnings and simplify.
* lisp/emacs-lisp/byte-opt.el (<, >, <=, >=, not, null, consp, listp)
(symbolp, stringp, string<, string-lessp, proper-list-p, logand)
(logior, logxor, lognot, car, cdr, car-safe, cdr-safe):
Remove superfluous byte-optimizer property.
(byte-optimize-predicate): Rename to byte-optimize-constant-args.
All uses changed.
2020-07-06 17:38:52 +02:00
|
|
|
|
form)
|
2003-01-05 00:28:18 +00:00
|
|
|
|
form))
|
1997-11-03 03:58:23 +00:00
|
|
|
|
|
2021-06-03 21:15:11 +02:00
|
|
|
|
(put 'cons 'byte-optimizer #'byte-optimize-cons)
|
|
|
|
|
(defun byte-optimize-cons (form)
|
2022-07-15 23:42:45 +02:00
|
|
|
|
(let ((tail (nth 2 form)))
|
|
|
|
|
(cond
|
|
|
|
|
;; (cons X nil) => (list X)
|
|
|
|
|
((null tail) `(list ,(nth 1 form)))
|
|
|
|
|
;; (cons X (list YS...)) -> (list X YS...)
|
|
|
|
|
((and (consp tail) (eq (car tail) 'list))
|
|
|
|
|
`(,(car tail) ,(nth 1 form) . ,(cdr tail)))
|
|
|
|
|
(t form))))
|
2021-06-03 21:15:11 +02:00
|
|
|
|
|
2022-07-15 21:28:30 +02:00
|
|
|
|
(put 'list 'byte-optimizer #'byte-optimize-list)
|
|
|
|
|
(defun byte-optimize-list (form)
|
|
|
|
|
;; (list) -> nil
|
|
|
|
|
(and (cdr form) form))
|
|
|
|
|
|
2022-07-15 18:55:30 +02:00
|
|
|
|
(put 'append 'byte-optimizer #'byte-optimize-append)
|
|
|
|
|
(defun byte-optimize-append (form)
|
|
|
|
|
;; There is (probably) too much code relying on `append' to return a
|
|
|
|
|
;; new list for us to do full constant-folding; these transformations
|
|
|
|
|
;; preserve the allocation semantics.
|
|
|
|
|
(and (cdr form) ; (append) -> nil
|
|
|
|
|
(named-let loop ((args (cdr form)) (newargs nil))
|
|
|
|
|
(let ((arg (car args))
|
|
|
|
|
(prev (car newargs)))
|
|
|
|
|
(cond
|
|
|
|
|
;; Flatten nested `append' forms.
|
|
|
|
|
((and (consp arg) (eq (car arg) 'append))
|
|
|
|
|
(loop (append (cdr arg) (cdr args)) newargs))
|
|
|
|
|
|
|
|
|
|
;; Merge consecutive `list' forms.
|
|
|
|
|
((and (consp arg) (eq (car arg) 'list)
|
|
|
|
|
newargs (consp prev) (eq (car prev) 'list))
|
|
|
|
|
(loop (cons (cons (car prev) (append (cdr prev) (cdr arg)))
|
|
|
|
|
(cdr args))
|
|
|
|
|
(cdr newargs)))
|
|
|
|
|
|
|
|
|
|
;; non-terminal arg
|
|
|
|
|
((cdr args)
|
|
|
|
|
(cond
|
|
|
|
|
((macroexp-const-p arg)
|
|
|
|
|
;; constant arg
|
2023-02-08 13:18:32 +01:00
|
|
|
|
(let ((val (byteopt--eval-const arg)))
|
2022-07-15 18:55:30 +02:00
|
|
|
|
(cond
|
|
|
|
|
;; Elide empty arguments (nil, empty string, etc).
|
|
|
|
|
((zerop (length val))
|
|
|
|
|
(loop (cdr args) newargs))
|
|
|
|
|
;; Merge consecutive constants.
|
|
|
|
|
((and newargs (macroexp-const-p prev))
|
|
|
|
|
(loop (cdr args)
|
|
|
|
|
(cons
|
|
|
|
|
(list 'quote
|
2023-02-08 13:18:32 +01:00
|
|
|
|
(append (byteopt--eval-const prev) val nil))
|
2022-07-15 18:55:30 +02:00
|
|
|
|
(cdr newargs))))
|
|
|
|
|
(t (loop (cdr args) (cons arg newargs))))))
|
|
|
|
|
|
|
|
|
|
;; (list CONSTANTS...) -> '(CONSTANTS...)
|
|
|
|
|
((and (consp arg) (eq (car arg) 'list)
|
|
|
|
|
(not (memq nil (mapcar #'macroexp-const-p (cdr arg)))))
|
|
|
|
|
(loop (cons (list 'quote (eval arg)) (cdr args)) newargs))
|
|
|
|
|
|
|
|
|
|
(t (loop (cdr args) (cons arg newargs)))))
|
|
|
|
|
|
|
|
|
|
;; At this point, `arg' is the last (tail) argument.
|
|
|
|
|
|
|
|
|
|
;; (append X) -> X
|
|
|
|
|
((null newargs) arg)
|
|
|
|
|
|
|
|
|
|
;; (append (list Xs...) nil) -> (list Xs...)
|
|
|
|
|
((and (null arg)
|
|
|
|
|
newargs (null (cdr newargs))
|
|
|
|
|
(consp prev) (eq (car prev) 'list))
|
|
|
|
|
prev)
|
|
|
|
|
|
|
|
|
|
;; (append '(X) Y) -> (cons 'X Y)
|
|
|
|
|
;; (append (list X) Y) -> (cons X Y)
|
|
|
|
|
((and newargs (null (cdr newargs))
|
|
|
|
|
(consp prev)
|
|
|
|
|
(cond ((eq (car prev) 'quote)
|
|
|
|
|
(and (consp (cadr prev))
|
|
|
|
|
(= (length (cadr prev)) 1)))
|
|
|
|
|
((eq (car prev) 'list)
|
|
|
|
|
(= (length (cdr prev)) 1))))
|
|
|
|
|
(list 'cons (if (eq (car prev) 'quote)
|
|
|
|
|
(macroexp-quote (caadr prev))
|
|
|
|
|
(cadr prev))
|
|
|
|
|
arg))
|
|
|
|
|
|
|
|
|
|
(t
|
|
|
|
|
(let ((new-form (cons 'append (nreverse (cons arg newargs)))))
|
|
|
|
|
(if (equal new-form form)
|
|
|
|
|
form
|
|
|
|
|
new-form))))))))
|
|
|
|
|
|
2002-12-12 20:28:32 +00:00
|
|
|
|
;; Fixme: delete-char -> delete-region (byte-coded)
|
|
|
|
|
|
2020-07-31 11:58:13 -04:00
|
|
|
|
(put 'set 'byte-optimizer #'byte-optimize-set)
|
2003-03-25 16:34:00 +00:00
|
|
|
|
(defun byte-optimize-set (form)
|
2022-09-22 14:15:56 +02:00
|
|
|
|
(pcase (cdr form)
|
|
|
|
|
;; Make sure we only turn `set' into `setq' for dynamic variables.
|
|
|
|
|
(`((quote ,(and var (guard (and (symbolp var)
|
|
|
|
|
(not (macroexp--const-symbol-p var))
|
|
|
|
|
(not (assq var byte-optimize--lexvars))))))
|
|
|
|
|
,newval)
|
|
|
|
|
`(setq ,var ,newval))
|
|
|
|
|
(`(,(and ml `(make-local-variable ,(and v `(quote ,_)))) ,newval)
|
|
|
|
|
`(progn ,ml (,(car form) ,v ,newval)))
|
|
|
|
|
(_ form)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; enumerating those functions which need not be called if the returned
|
|
|
|
|
;; value is not used. That is, something like
|
|
|
|
|
;; (progn (list (something-with-side-effects) (yow))
|
|
|
|
|
;; (foo))
|
|
|
|
|
;; may safely be turned into
|
|
|
|
|
;; (progn (progn (something-with-side-effects) (yow))
|
|
|
|
|
;; (foo))
|
|
|
|
|
;; Further optimizations will turn (progn (list 1 2 3) 'foo) into 'foo.
|
|
|
|
|
|
|
|
|
|
;; Some of these functions have the side effect of allocating memory
|
|
|
|
|
;; and it would be incorrect to replace two calls with one.
|
|
|
|
|
;; But we don't try to do those kinds of optimizations,
|
|
|
|
|
;; so it is safe to list such functions here.
|
|
|
|
|
;; Some of these functions return values that depend on environment
|
|
|
|
|
;; state, so that constant folding them would be wrong,
|
|
|
|
|
;; but we don't do constant folding based on this list.
|
|
|
|
|
|
|
|
|
|
;; However, at present the only optimization we normally do
|
|
|
|
|
;; is delete calls that need not occur, and we only do that
|
|
|
|
|
;; with the error-free functions.
|
|
|
|
|
|
|
|
|
|
;; I wonder if I missed any :-\)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(let ((side-effect-free-fns
|
1993-12-23 05:00:49 +00:00
|
|
|
|
'(% * + - / /= 1+ 1- < <= = > >= abs acos append aref ash asin atan
|
2020-10-31 14:16:25 +01:00
|
|
|
|
assq
|
2021-12-19 12:38:17 +01:00
|
|
|
|
base64-decode-string base64-encode-string base64url-encode-string
|
2020-11-01 15:57:12 +01:00
|
|
|
|
bool-vector-count-consecutive bool-vector-count-population
|
|
|
|
|
bool-vector-subsetp
|
1993-12-23 05:00:49 +00:00
|
|
|
|
boundp buffer-file-name buffer-local-variables buffer-modified-p
|
2002-03-31 16:22:58 +00:00
|
|
|
|
buffer-substring byte-code-function-p
|
2000-05-21 17:24:19 +00:00
|
|
|
|
capitalize car-less-than-car car cdr ceiling char-after char-before
|
* emacs-lisp/byte-opt.el (toplevel): Add compare-window-configurations,
frame-first-window, frame-root-window, frame-selected-window,
minibuffer-selected-window, minibuffer-window,
window-absolute-pixel-edges, window-at, window-body-height,
window-body-width, window-display-table, window-combination-limit,
window-frame, window-fringes, window-inside-absolute-pixel-edges,
window-inside-edges, window-inside-pixel-edges, window-left-child,
window-left-column, window-margins, window-next-buffers,
window-next-sibling, window-new-normal, window-new-total,
window-normal-size, window-parameter, window-parameters, window-parent,
window-pixel-edges, window-point, window-prev-buffers,
window-prev-sibling, window-redisplay-end-trigger, window-scroll-bars,
window-start, window-text-height, window-top-child, window-top-line,
window-total-height, window-total-width and window-use-time to the list
of functions without side-effects.
(toplevel): Add window-valid-p to the list of error-free functions
without side-effects.
2012-11-06 11:37:06 +04:00
|
|
|
|
char-equal char-to-string char-width compare-strings
|
2022-05-20 04:23:32 +02:00
|
|
|
|
window-configuration-equal-p concat coordinates-in-window-p
|
2020-11-01 15:57:12 +01:00
|
|
|
|
copy-alist copy-sequence copy-marker copysign cos count-lines
|
Fix byte-opt lists of pure functions etc.
This fixes a bug where a byte-compiler running on 64-bit Emacs
optimized (lsh -1 -1) to #x1fffffffffffffff, an optimization
that is incorrect for .elc files intended for either 32- or
64-bit Emacs. While I was in the neighborhood, I noticed other
glitches in the lists of pure and side-effect-free functions, and
fixed the errors that I found.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
Move some functions here from side-effect-and-error-free-fns,
since they can now signal errors. The affected functions are
current-time-string, current-time-zone,
line-beginning-position, line-end-position. Rename langinfo
to locale-info. Add logcount. Remove string-to-int.
(side-effect-and-error-free-fns): Remove minibuffer-window, a
function that can signal errors, and that is already in
side-effect-free-fns.
(pure-fns): Remove ash, lsh, and logb, since they are
platform-dependent and .elc files should be
platform-independent. Add %, logand, logcount. Sort.
Clarify what is meant by “pure”.
2018-03-22 11:25:42 -07:00
|
|
|
|
current-time-string current-time-zone
|
2008-03-25 23:27:11 +00:00
|
|
|
|
decode-char
|
2002-03-31 16:22:58 +00:00
|
|
|
|
decode-time default-boundp default-value documentation downcase
|
2003-09-08 12:53:41 +00:00
|
|
|
|
elt encode-char exp expt encode-time error-message-string
|
2002-03-31 16:22:58 +00:00
|
|
|
|
fboundp fceiling featurep ffloor
|
1992-07-10 22:06:47 +00:00
|
|
|
|
file-directory-p file-exists-p file-locked-p file-name-absolute-p
|
2021-08-03 19:41:57 +02:00
|
|
|
|
file-name-concat
|
1992-07-10 22:06:47 +00:00
|
|
|
|
file-newer-than-file-p file-readable-p file-symlink-p file-writable-p
|
* emacs-lisp/byte-opt.el (toplevel): Add compare-window-configurations,
frame-first-window, frame-root-window, frame-selected-window,
minibuffer-selected-window, minibuffer-window,
window-absolute-pixel-edges, window-at, window-body-height,
window-body-width, window-display-table, window-combination-limit,
window-frame, window-fringes, window-inside-absolute-pixel-edges,
window-inside-edges, window-inside-pixel-edges, window-left-child,
window-left-column, window-margins, window-next-buffers,
window-next-sibling, window-new-normal, window-new-total,
window-normal-size, window-parameter, window-parameters, window-parent,
window-pixel-edges, window-point, window-prev-buffers,
window-prev-sibling, window-redisplay-end-trigger, window-scroll-bars,
window-start, window-text-height, window-top-child, window-top-line,
window-total-height, window-total-width and window-use-time to the list
of functions without side-effects.
(toplevel): Add window-valid-p to the list of error-free functions
without side-effects.
2012-11-06 11:37:06 +04:00
|
|
|
|
float float-time floor format format-time-string frame-first-window
|
|
|
|
|
frame-root-window frame-selected-window
|
|
|
|
|
frame-visible-p fround ftruncate
|
1999-12-18 17:28:36 +00:00
|
|
|
|
get gethash get-buffer get-buffer-window getenv get-file-buffer
|
|
|
|
|
hash-table-count
|
2020-11-01 15:57:12 +01:00
|
|
|
|
int-to-string intern-soft isnan
|
1999-09-09 20:04:17 +00:00
|
|
|
|
keymap-parent
|
2020-12-27 09:00:23 +01:00
|
|
|
|
lax-plist-get ldexp
|
|
|
|
|
length length< length> length=
|
2022-08-21 16:17:45 +02:00
|
|
|
|
line-beginning-position line-end-position pos-bol pos-eol
|
Fix byte-opt lists of pure functions etc.
This fixes a bug where a byte-compiler running on 64-bit Emacs
optimized (lsh -1 -1) to #x1fffffffffffffff, an optimization
that is incorrect for .elc files intended for either 32- or
64-bit Emacs. While I was in the neighborhood, I noticed other
glitches in the lists of pure and side-effect-free functions, and
fixed the errors that I found.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
Move some functions here from side-effect-and-error-free-fns,
since they can now signal errors. The affected functions are
current-time-string, current-time-zone,
line-beginning-position, line-end-position. Rename langinfo
to locale-info. Add logcount. Remove string-to-int.
(side-effect-and-error-free-fns): Remove minibuffer-window, a
function that can signal errors, and that is already in
side-effect-free-fns.
(pure-fns): Remove ash, lsh, and logb, since they are
platform-dependent and .elc files should be
platform-independent. Add %, logand, logcount. Sort.
Clarify what is meant by “pure”.
2018-03-22 11:25:42 -07:00
|
|
|
|
local-variable-if-set-p local-variable-p locale-info
|
|
|
|
|
log log10 logand logb logcount logior lognot logxor lsh
|
2021-04-21 17:27:14 +02:00
|
|
|
|
make-byte-code make-list make-string make-symbol mark marker-buffer max
|
2021-08-03 15:28:10 +02:00
|
|
|
|
match-beginning match-end
|
2020-11-01 15:57:12 +01:00
|
|
|
|
member memq memql min minibuffer-selected-window minibuffer-window
|
* emacs-lisp/byte-opt.el (toplevel): Add compare-window-configurations,
frame-first-window, frame-root-window, frame-selected-window,
minibuffer-selected-window, minibuffer-window,
window-absolute-pixel-edges, window-at, window-body-height,
window-body-width, window-display-table, window-combination-limit,
window-frame, window-fringes, window-inside-absolute-pixel-edges,
window-inside-edges, window-inside-pixel-edges, window-left-child,
window-left-column, window-margins, window-next-buffers,
window-next-sibling, window-new-normal, window-new-total,
window-normal-size, window-parameter, window-parameters, window-parent,
window-pixel-edges, window-point, window-prev-buffers,
window-prev-sibling, window-redisplay-end-trigger, window-scroll-bars,
window-start, window-text-height, window-top-child, window-top-line,
window-total-height, window-total-width and window-use-time to the list
of functions without side-effects.
(toplevel): Add window-valid-p to the list of error-free functions
without side-effects.
2012-11-06 11:37:06 +04:00
|
|
|
|
mod multibyte-char-to-unibyte next-window nth nthcdr number-to-string
|
2022-06-27 12:22:05 +02:00
|
|
|
|
parse-colon-path
|
2002-03-31 16:22:58 +00:00
|
|
|
|
prefix-numeric-value previous-window prin1-to-string propertize
|
2009-09-10 06:21:48 +00:00
|
|
|
|
degrees-to-radians
|
2020-11-01 15:57:12 +01:00
|
|
|
|
radians-to-degrees rassq rassoc read-from-string regexp-opt
|
|
|
|
|
regexp-quote region-beginning region-end reverse round
|
2020-09-25 14:30:13 +02:00
|
|
|
|
sin sqrt string string< string= string-equal string-lessp
|
2022-07-28 12:35:21 -04:00
|
|
|
|
string> string-greaterp string-empty-p string-blank-p
|
2020-09-25 14:30:13 +02:00
|
|
|
|
string-search string-to-char
|
2020-11-01 15:57:12 +01:00
|
|
|
|
string-to-number string-to-syntax substring
|
2016-04-08 14:02:48 -07:00
|
|
|
|
sxhash sxhash-equal sxhash-eq sxhash-eql
|
|
|
|
|
symbol-function symbol-name symbol-plist symbol-value string-make-unibyte
|
2002-11-19 17:59:30 +00:00
|
|
|
|
string-make-multibyte string-as-multibyte string-as-unibyte
|
2003-09-08 12:53:41 +00:00
|
|
|
|
string-to-multibyte
|
2022-07-13 13:46:52 +02:00
|
|
|
|
take tan time-convert truncate
|
2002-03-31 16:22:58 +00:00
|
|
|
|
unibyte-char-to-multibyte upcase user-full-name
|
2012-04-09 20:36:01 +08:00
|
|
|
|
user-login-name user-original-login-name custom-variable-p
|
2002-03-31 16:22:58 +00:00
|
|
|
|
vconcat
|
* emacs-lisp/byte-opt.el (toplevel): Add compare-window-configurations,
frame-first-window, frame-root-window, frame-selected-window,
minibuffer-selected-window, minibuffer-window,
window-absolute-pixel-edges, window-at, window-body-height,
window-body-width, window-display-table, window-combination-limit,
window-frame, window-fringes, window-inside-absolute-pixel-edges,
window-inside-edges, window-inside-pixel-edges, window-left-child,
window-left-column, window-margins, window-next-buffers,
window-next-sibling, window-new-normal, window-new-total,
window-normal-size, window-parameter, window-parameters, window-parent,
window-pixel-edges, window-point, window-prev-buffers,
window-prev-sibling, window-redisplay-end-trigger, window-scroll-bars,
window-start, window-text-height, window-top-child, window-top-line,
window-total-height, window-total-width and window-use-time to the list
of functions without side-effects.
(toplevel): Add window-valid-p to the list of error-free functions
without side-effects.
2012-11-06 11:37:06 +04:00
|
|
|
|
window-absolute-pixel-edges window-at window-body-height
|
|
|
|
|
window-body-width window-buffer window-dedicated-p window-display-table
|
|
|
|
|
window-combination-limit window-edges window-frame window-fringes
|
|
|
|
|
window-height window-hscroll window-inside-edges
|
|
|
|
|
window-inside-absolute-pixel-edges window-inside-pixel-edges
|
|
|
|
|
window-left-child window-left-column window-margins window-minibuffer-p
|
|
|
|
|
window-next-buffers window-next-sibling window-new-normal
|
|
|
|
|
window-new-total window-normal-size window-parameter window-parameters
|
Fix minor quoting problems in doc strings
These were glitches regardless of how or whether we tackle the
problem of grave accent in doc strings.
* lisp/calc/calc-aent.el (math-restore-placeholders):
* lisp/ido.el (ido-ignore-buffers, ido-ignore-files):
* lisp/leim/quail/cyrillic.el ("bulgarian-alt-phonetic"):
* lisp/leim/quail/hebrew.el ("hebrew-new")
("hebrew-biblical-sil"):
* lisp/leim/quail/thai.el ("thai-kesmanee"):
* lisp/progmodes/idlw-shell.el (idlwave-shell-file-name-chars):
Used curved quotes to avoid ambiguities like ‘`''’ in doc strings.
* lisp/calendar/calendar.el (calendar-month-abbrev-array):
* lisp/cedet/semantic/mru-bookmark.el (semantic-mrub-cache-flush-fcn):
* lisp/cedet/semantic/symref.el (semantic-symref-tool-baseclass):
* lisp/cedet/semantic/tag.el (semantic-tag-copy)
(semantic-tag-components):
* lisp/cedet/srecode/cpp.el (srecode-semantic-handle-:cpp):
* lisp/cedet/srecode/texi.el (srecode-texi-texify-docstring):
* lisp/emacs-lisp/byte-opt.el (byte-optimize-all-constp):
* lisp/emacs-lisp/checkdoc.el (checkdoc-message-text-engine):
* lisp/emacs-lisp/generator.el (iter-next):
* lisp/gnus/gnus-art.el (gnus-treat-strip-list-identifiers)
(gnus-article-mode-syntax-table):
* lisp/net/rlogin.el (rlogin-directory-tracking-mode):
* lisp/net/soap-client.el (soap-wsdl-get):
* lisp/net/telnet.el (telnet-mode):
* lisp/org/org-compat.el (org-number-sequence):
* lisp/org/org.el (org-remove-highlights-with-change)
(org-structure-template-alist):
* lisp/org/ox-html.el (org-html-link-org-files-as-html):
* lisp/play/handwrite.el (handwrite-10pt, handwrite-11pt)
(handwrite-12pt, handwrite-13pt):
* lisp/progmodes/f90.el (f90-mode, f90-abbrev-start):
* lisp/progmodes/idlwave.el (idlwave-mode, idlwave-check-abbrev):
* lisp/progmodes/verilog-mode.el (verilog-tool)
(verilog-string-replace-matches, verilog-preprocess)
(verilog-auto-insert-lisp, verilog-auto-insert-last):
* lisp/textmodes/makeinfo.el (makeinfo-options):
* src/font.c (Ffont_spec):
Fix minor quoting problems in doc strings, e.g., missing quote,
``x'' where `x' was meant, etc.
* lisp/erc/erc-backend.el (erc-process-sentinel-2):
Fix minor quoting problem in other string.
* lisp/leim/quail/ethiopic.el ("ethiopic"):
* lisp/term/tvi970.el (tvi970-set-keypad-mode):
Omit unnecessary quotes.
* lisp/faces.el (set-face-attribute, set-face-underline)
(set-face-inverse-video, x-create-frame-with-faces):
* lisp/gnus/gnus-group.el (gnus-group-nnimap-edit-acl):
* lisp/mail/supercite.el (sc-attribs-%@-addresses)
(sc-attribs-!-addresses, sc-attribs-<>-addresses):
* lisp/net/tramp.el (tramp-methods):
* lisp/recentf.el (recentf-show-file-shortcuts-flag):
* lisp/textmodes/artist.el (artist-ellipse-right-char)
(artist-ellipse-left-char, artist-vaporize-fuzziness)
(artist-spray-chars, artist-mode, artist-replace-string)
(artist-put-pixel, artist-text-see-thru):
* lisp/vc/ediff-util.el (ediff-submit-report):
* lisp/vc/log-edit.el (log-edit-changelog-full-paragraphs):
Use double-quotes rather than TeX markup in doc strings.
* lisp/skeleton.el (skeleton-pair-insert-maybe):
Reword to avoid the need for grave accent and apostrophe.
* lisp/xt-mouse.el (xterm-mouse-tracking-enable-sequence):
Don't use grave and acute accents to quote.
2015-05-19 14:59:15 -07:00
|
|
|
|
window-parent window-pixel-edges window-point window-prev-buffers
|
2022-07-31 01:44:22 +02:00
|
|
|
|
window-prev-sibling window-scroll-bars
|
* emacs-lisp/byte-opt.el (toplevel): Add compare-window-configurations,
frame-first-window, frame-root-window, frame-selected-window,
minibuffer-selected-window, minibuffer-window,
window-absolute-pixel-edges, window-at, window-body-height,
window-body-width, window-display-table, window-combination-limit,
window-frame, window-fringes, window-inside-absolute-pixel-edges,
window-inside-edges, window-inside-pixel-edges, window-left-child,
window-left-column, window-margins, window-next-buffers,
window-next-sibling, window-new-normal, window-new-total,
window-normal-size, window-parameter, window-parameters, window-parent,
window-pixel-edges, window-point, window-prev-buffers,
window-prev-sibling, window-redisplay-end-trigger, window-scroll-bars,
window-start, window-text-height, window-top-child, window-top-line,
window-total-height, window-total-width and window-use-time to the list
of functions without side-effects.
(toplevel): Add window-valid-p to the list of error-free functions
without side-effects.
2012-11-06 11:37:06 +04:00
|
|
|
|
window-start window-text-height window-top-child window-top-line
|
|
|
|
|
window-total-height window-total-width window-use-time window-vscroll
|
|
|
|
|
window-width zerop))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(side-effect-and-error-free-fns
|
2021-02-20 13:44:19 +01:00
|
|
|
|
'(always arrayp atom
|
2018-07-08 09:36:37 -06:00
|
|
|
|
bignump bobp bolp bool-vector-p
|
2002-03-31 16:22:58 +00:00
|
|
|
|
buffer-end buffer-list buffer-size buffer-string bufferp
|
2002-05-23 18:15:02 +00:00
|
|
|
|
car-safe case-table-p cdr-safe char-or-string-p characterp
|
2002-06-27 21:28:58 +00:00
|
|
|
|
charsetp commandp cons consp
|
1999-09-09 20:04:17 +00:00
|
|
|
|
current-buffer current-global-map current-indentation
|
2002-03-31 16:22:58 +00:00
|
|
|
|
current-local-map current-minor-mode-maps current-time
|
|
|
|
|
eobp eolp eq equal eventp
|
2018-07-08 09:36:37 -06:00
|
|
|
|
fixnump floatp following-char framep
|
1993-12-23 05:00:49 +00:00
|
|
|
|
get-largest-window get-lru-window
|
1999-12-18 17:28:36 +00:00
|
|
|
|
hash-table-p
|
2021-06-10 21:27:16 +02:00
|
|
|
|
;; `ignore' isn't here because we don't want calls to it elided;
|
|
|
|
|
;; see `byte-compile-ignore'.
|
|
|
|
|
identity integerp integer-or-marker-p interactive-p
|
1993-12-23 05:00:49 +00:00
|
|
|
|
invocation-directory invocation-name
|
2017-05-26 22:45:58 +01:00
|
|
|
|
keymapp keywordp
|
Fix byte-opt lists of pure functions etc.
This fixes a bug where a byte-compiler running on 64-bit Emacs
optimized (lsh -1 -1) to #x1fffffffffffffff, an optimization
that is incorrect for .elc files intended for either 32- or
64-bit Emacs. While I was in the neighborhood, I noticed other
glitches in the lists of pure and side-effect-free functions, and
fixed the errors that I found.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
Move some functions here from side-effect-and-error-free-fns,
since they can now signal errors. The affected functions are
current-time-string, current-time-zone,
line-beginning-position, line-end-position. Rename langinfo
to locale-info. Add logcount. Remove string-to-int.
(side-effect-and-error-free-fns): Remove minibuffer-window, a
function that can signal errors, and that is already in
side-effect-free-fns.
(pure-fns): Remove ash, lsh, and logb, since they are
platform-dependent and .elc files should be
platform-independent. Add %, logand, logcount. Sort.
Clarify what is meant by “pure”.
2018-03-22 11:25:42 -07:00
|
|
|
|
list listp
|
2021-04-21 17:27:14 +02:00
|
|
|
|
make-marker mark-marker markerp max-char
|
Fix byte-opt lists of pure functions etc.
This fixes a bug where a byte-compiler running on 64-bit Emacs
optimized (lsh -1 -1) to #x1fffffffffffffff, an optimization
that is incorrect for .elc files intended for either 32- or
64-bit Emacs. While I was in the neighborhood, I noticed other
glitches in the lists of pure and side-effect-free functions, and
fixed the errors that I found.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
Move some functions here from side-effect-and-error-free-fns,
since they can now signal errors. The affected functions are
current-time-string, current-time-zone,
line-beginning-position, line-end-position. Rename langinfo
to locale-info. Add logcount. Remove string-to-int.
(side-effect-and-error-free-fns): Remove minibuffer-window, a
function that can signal errors, and that is already in
side-effect-free-fns.
(pure-fns): Remove ash, lsh, and logb, since they are
platform-dependent and .elc files should be
platform-independent. Add %, logand, logcount. Sort.
Clarify what is meant by “pure”.
2018-03-22 11:25:42 -07:00
|
|
|
|
memory-limit
|
1993-12-23 05:00:49 +00:00
|
|
|
|
mouse-movement-p
|
|
|
|
|
natnump nlistp not null number-or-marker-p numberp
|
|
|
|
|
one-window-p overlayp
|
2002-06-27 21:28:58 +00:00
|
|
|
|
point point-marker point-min point-max preceding-char primary-charset
|
2022-07-28 12:35:21 -04:00
|
|
|
|
processp proper-list-p
|
1999-09-09 20:04:17 +00:00
|
|
|
|
recent-keys recursion-depth
|
2002-03-31 16:22:58 +00:00
|
|
|
|
safe-length selected-frame selected-window sequencep
|
|
|
|
|
standard-case-table standard-syntax-table stringp subrp symbolp
|
|
|
|
|
syntax-table syntax-table-p
|
1999-09-09 20:04:17 +00:00
|
|
|
|
this-command-keys this-command-keys-vector this-single-command-keys
|
2020-11-01 15:57:12 +01:00
|
|
|
|
this-single-command-raw-keys type-of
|
1993-12-23 05:00:49 +00:00
|
|
|
|
user-real-login-name user-real-uid user-uid
|
1999-09-09 20:04:17 +00:00
|
|
|
|
vector vectorp visible-frame-list
|
* emacs-lisp/byte-opt.el (toplevel): Add compare-window-configurations,
frame-first-window, frame-root-window, frame-selected-window,
minibuffer-selected-window, minibuffer-window,
window-absolute-pixel-edges, window-at, window-body-height,
window-body-width, window-display-table, window-combination-limit,
window-frame, window-fringes, window-inside-absolute-pixel-edges,
window-inside-edges, window-inside-pixel-edges, window-left-child,
window-left-column, window-margins, window-next-buffers,
window-next-sibling, window-new-normal, window-new-total,
window-normal-size, window-parameter, window-parameters, window-parent,
window-pixel-edges, window-point, window-prev-buffers,
window-prev-sibling, window-redisplay-end-trigger, window-scroll-bars,
window-start, window-text-height, window-top-child, window-top-line,
window-total-height, window-total-width and window-use-time to the list
of functions without side-effects.
(toplevel): Add window-valid-p to the list of error-free functions
without side-effects.
2012-11-06 11:37:06 +04:00
|
|
|
|
wholenump window-configuration-p window-live-p
|
|
|
|
|
window-valid-p windowp)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(while side-effect-free-fns
|
|
|
|
|
(put (car side-effect-free-fns) 'side-effect-free t)
|
|
|
|
|
(setq side-effect-free-fns (cdr side-effect-free-fns)))
|
|
|
|
|
(while side-effect-and-error-free-fns
|
|
|
|
|
(put (car side-effect-and-error-free-fns) 'side-effect-free 'error-free)
|
|
|
|
|
(setq side-effect-and-error-free-fns (cdr side-effect-and-error-free-fns)))
|
|
|
|
|
nil)
|
|
|
|
|
|
2007-04-11 17:10:42 +00:00
|
|
|
|
|
Fix byte-opt lists of pure functions etc.
This fixes a bug where a byte-compiler running on 64-bit Emacs
optimized (lsh -1 -1) to #x1fffffffffffffff, an optimization
that is incorrect for .elc files intended for either 32- or
64-bit Emacs. While I was in the neighborhood, I noticed other
glitches in the lists of pure and side-effect-free functions, and
fixed the errors that I found.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
Move some functions here from side-effect-and-error-free-fns,
since they can now signal errors. The affected functions are
current-time-string, current-time-zone,
line-beginning-position, line-end-position. Rename langinfo
to locale-info. Add logcount. Remove string-to-int.
(side-effect-and-error-free-fns): Remove minibuffer-window, a
function that can signal errors, and that is already in
side-effect-free-fns.
(pure-fns): Remove ash, lsh, and logb, since they are
platform-dependent and .elc files should be
platform-independent. Add %, logand, logcount. Sort.
Clarify what is meant by “pure”.
2018-03-22 11:25:42 -07:00
|
|
|
|
;; Pure functions are side-effect free functions whose values depend
|
|
|
|
|
;; only on their arguments, not on the platform. For these functions,
|
|
|
|
|
;; calls with constant arguments can be evaluated at compile time.
|
2020-07-05 13:47:34 +02:00
|
|
|
|
;; For example, ash is pure since its results are machine-independent,
|
|
|
|
|
;; whereas lsh is not pure because (lsh -1 -1)'s value depends on the
|
|
|
|
|
;; fixnum range.
|
Fix byte-opt lists of pure functions etc.
This fixes a bug where a byte-compiler running on 64-bit Emacs
optimized (lsh -1 -1) to #x1fffffffffffffff, an optimization
that is incorrect for .elc files intended for either 32- or
64-bit Emacs. While I was in the neighborhood, I noticed other
glitches in the lists of pure and side-effect-free functions, and
fixed the errors that I found.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
Move some functions here from side-effect-and-error-free-fns,
since they can now signal errors. The affected functions are
current-time-string, current-time-zone,
line-beginning-position, line-end-position. Rename langinfo
to locale-info. Add logcount. Remove string-to-int.
(side-effect-and-error-free-fns): Remove minibuffer-window, a
function that can signal errors, and that is already in
side-effect-free-fns.
(pure-fns): Remove ash, lsh, and logb, since they are
platform-dependent and .elc files should be
platform-independent. Add %, logand, logcount. Sort.
Clarify what is meant by “pure”.
2018-03-22 11:25:42 -07:00
|
|
|
|
;;
|
|
|
|
|
;; When deciding whether a function is pure, do not worry about
|
|
|
|
|
;; mutable strings or markers, as they are so unlikely in real code
|
|
|
|
|
;; that they are not worth worrying about. Thus string-to-char is
|
|
|
|
|
;; pure even though it might return different values if a string is
|
|
|
|
|
;; changed, and logand is pure even though it might return different
|
|
|
|
|
;; values if a marker is moved.
|
2007-04-11 17:10:42 +00:00
|
|
|
|
|
|
|
|
|
(let ((pure-fns
|
2020-07-05 13:47:34 +02:00
|
|
|
|
'(concat regexp-opt regexp-quote
|
|
|
|
|
string-to-char string-to-syntax symbol-name
|
|
|
|
|
eq eql
|
2020-11-01 15:01:31 +01:00
|
|
|
|
= /= < <= >= > min max
|
2020-07-05 13:47:34 +02:00
|
|
|
|
+ - * / % mod abs ash 1+ 1- sqrt
|
|
|
|
|
logand logior lognot logxor logcount
|
|
|
|
|
copysign isnan ldexp float logb
|
|
|
|
|
floor ceiling round truncate
|
|
|
|
|
ffloor fceiling fround ftruncate
|
2021-02-28 19:02:15 +01:00
|
|
|
|
string= string-equal string< string-lessp string> string-greaterp
|
2022-07-28 12:35:21 -04:00
|
|
|
|
string-empty-p string-blank-p
|
2020-09-25 17:00:17 +02:00
|
|
|
|
string-search
|
2020-11-01 15:01:31 +01:00
|
|
|
|
consp atom listp nlistp proper-list-p
|
2020-07-05 13:47:34 +02:00
|
|
|
|
sequencep arrayp vectorp stringp bool-vector-p hash-table-p
|
|
|
|
|
null not
|
|
|
|
|
numberp integerp floatp natnump characterp
|
|
|
|
|
integer-or-marker-p number-or-marker-p char-or-string-p
|
|
|
|
|
symbolp keywordp
|
|
|
|
|
type-of
|
|
|
|
|
identity ignore
|
|
|
|
|
|
|
|
|
|
;; The following functions are pure up to mutation of their
|
|
|
|
|
;; arguments. This is pure enough for the purposes of
|
|
|
|
|
;; constant folding, but not necessarily for all kinds of
|
|
|
|
|
;; code motion.
|
2022-07-13 13:46:52 +02:00
|
|
|
|
car cdr car-safe cdr-safe nth nthcdr last take
|
2020-07-05 13:47:34 +02:00
|
|
|
|
equal
|
|
|
|
|
length safe-length
|
|
|
|
|
memq memql member
|
|
|
|
|
;; `assoc' and `assoc-default' are excluded since they are
|
|
|
|
|
;; impure if the test function is (consider `string-match').
|
|
|
|
|
assq rassq rassoc
|
2022-06-27 12:22:05 +02:00
|
|
|
|
lax-plist-get
|
2020-07-05 13:47:34 +02:00
|
|
|
|
aref elt
|
2021-12-19 12:38:17 +01:00
|
|
|
|
base64-decode-string base64-encode-string base64url-encode-string
|
2020-07-05 13:47:34 +02:00
|
|
|
|
bool-vector-subsetp
|
|
|
|
|
bool-vector-count-population bool-vector-count-consecutive
|
|
|
|
|
)))
|
2007-04-11 17:10:42 +00:00
|
|
|
|
(while pure-fns
|
|
|
|
|
(put (car pure-fns) 'pure t)
|
|
|
|
|
(setq pure-fns (cdr pure-fns)))
|
|
|
|
|
nil)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defconst byte-constref-ops
|
|
|
|
|
'(byte-constant byte-constant2 byte-varref byte-varset byte-varbind))
|
|
|
|
|
|
2011-02-21 17:34:51 -05:00
|
|
|
|
;; Used and set dynamically in byte-decompile-bytecode-1.
|
|
|
|
|
(defvar bytedecomp-op)
|
|
|
|
|
(defvar bytedecomp-ptr)
|
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; This function extracts the bitfields from variable-length opcodes.
|
|
|
|
|
;; Originally defined in disass.el (which no longer uses it.)
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(defun disassemble-offset (bytes)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
"Don't call this!"
|
2011-03-16 16:08:39 -04:00
|
|
|
|
;; Fetch and return the offset for the current opcode.
|
|
|
|
|
;; Return nil if this opcode has no offset.
|
Introduce new bytecodes for efficient catch/condition-case in lexbind.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Optimize under `condition-case' and `catch' if
byte-compile--use-old-handlers is nil.
(disassemble-offset): Handle new bytecodes.
* lisp/emacs-lisp/bytecomp.el (byte-pushcatch, byte-pushconditioncase)
(byte-pophandler): New byte codes.
(byte-goto-ops): Adjust accordingly.
(byte-compile--use-old-handlers): New var.
(byte-compile-catch): Use new byte codes depending on
byte-compile--use-old-handlers.
(byte-compile-condition-case--old): Rename from
byte-compile-condition-case.
(byte-compile-condition-case--new): New function.
(byte-compile-condition-case): New function that dispatches depending
on byte-compile--use-old-handlers.
(byte-compile-unwind-protect): Pass a function to byte-unwind-protect
when we can.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv-analyse-form): Adjust for
the new compilation scheme using the new byte-codes.
* src/alloc.c (Fgarbage_collect): Merge scans of handlerlist and catchlist,
and make them unconditional now that they're heap-allocated.
* src/bytecode.c (BYTE_CODES): Add Bpushcatch, Bpushconditioncase
and Bpophandler.
(bcall0): New function.
(exec_byte_code): Add corresponding cases. Improve error message when
encountering an invalid byte-code. Let Bunwind_protect accept
a function (rather than a list of expressions) as argument.
* src/eval.c (catchlist): Remove (merge with handlerlist).
(handlerlist, lisp_eval_depth): Not static any more.
(internal_catch, internal_condition_case, internal_condition_case_1)
(internal_condition_case_2, internal_condition_case_n):
Use PUSH_HANDLER.
(unwind_to_catch, Fthrow, Fsignal): Adjust to merged
handlerlist/catchlist.
(internal_lisp_condition_case): Use PUSH_HANDLER. Adjust to new
handlerlist which can only handle a single condition-case handler at
a time.
(find_handler_clause): Simplify since we only a single branch here
any more.
* src/lisp.h (struct handler): Merge struct handler and struct catchtag.
(PUSH_HANDLER): New macro.
(catchlist): Remove.
(handlerlist): Always declare.
2013-10-03 00:58:56 -04:00
|
|
|
|
(cond ((< bytedecomp-op byte-pophandler)
|
2010-11-05 00:32:16 -07:00
|
|
|
|
(let ((tem (logand bytedecomp-op 7)))
|
|
|
|
|
(setq bytedecomp-op (logand bytedecomp-op 248))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(cond ((eq tem 6)
|
2010-11-05 00:32:16 -07:00
|
|
|
|
;; Offset in next byte.
|
|
|
|
|
(setq bytedecomp-ptr (1+ bytedecomp-ptr))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(aref bytes bytedecomp-ptr))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
((eq tem 7)
|
2010-11-05 00:32:16 -07:00
|
|
|
|
;; Offset in next 2 bytes.
|
|
|
|
|
(setq bytedecomp-ptr (1+ bytedecomp-ptr))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(+ (aref bytes bytedecomp-ptr)
|
2010-11-05 00:32:16 -07:00
|
|
|
|
(progn (setq bytedecomp-ptr (1+ bytedecomp-ptr))
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
|
(ash (aref bytes bytedecomp-ptr) 8))))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(t tem)))) ;Offset was in opcode.
|
2010-11-05 00:32:16 -07:00
|
|
|
|
((>= bytedecomp-op byte-constant)
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(prog1 (- bytedecomp-op byte-constant) ;Offset in opcode.
|
2010-11-05 00:32:16 -07:00
|
|
|
|
(setq bytedecomp-op byte-constant)))
|
2010-12-10 19:13:08 -05:00
|
|
|
|
((or (and (>= bytedecomp-op byte-constant2)
|
|
|
|
|
(<= bytedecomp-op byte-goto-if-not-nil-else-pop))
|
Introduce new bytecodes for efficient catch/condition-case in lexbind.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Optimize under `condition-case' and `catch' if
byte-compile--use-old-handlers is nil.
(disassemble-offset): Handle new bytecodes.
* lisp/emacs-lisp/bytecomp.el (byte-pushcatch, byte-pushconditioncase)
(byte-pophandler): New byte codes.
(byte-goto-ops): Adjust accordingly.
(byte-compile--use-old-handlers): New var.
(byte-compile-catch): Use new byte codes depending on
byte-compile--use-old-handlers.
(byte-compile-condition-case--old): Rename from
byte-compile-condition-case.
(byte-compile-condition-case--new): New function.
(byte-compile-condition-case): New function that dispatches depending
on byte-compile--use-old-handlers.
(byte-compile-unwind-protect): Pass a function to byte-unwind-protect
when we can.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv-analyse-form): Adjust for
the new compilation scheme using the new byte-codes.
* src/alloc.c (Fgarbage_collect): Merge scans of handlerlist and catchlist,
and make them unconditional now that they're heap-allocated.
* src/bytecode.c (BYTE_CODES): Add Bpushcatch, Bpushconditioncase
and Bpophandler.
(bcall0): New function.
(exec_byte_code): Add corresponding cases. Improve error message when
encountering an invalid byte-code. Let Bunwind_protect accept
a function (rather than a list of expressions) as argument.
* src/eval.c (catchlist): Remove (merge with handlerlist).
(handlerlist, lisp_eval_depth): Not static any more.
(internal_catch, internal_condition_case, internal_condition_case_1)
(internal_condition_case_2, internal_condition_case_n):
Use PUSH_HANDLER.
(unwind_to_catch, Fthrow, Fsignal): Adjust to merged
handlerlist/catchlist.
(internal_lisp_condition_case): Use PUSH_HANDLER. Adjust to new
handlerlist which can only handle a single condition-case handler at
a time.
(find_handler_clause): Simplify since we only a single branch here
any more.
* src/lisp.h (struct handler): Merge struct handler and struct catchtag.
(PUSH_HANDLER): New macro.
(catchlist): Remove.
(handlerlist): Always declare.
2013-10-03 00:58:56 -04:00
|
|
|
|
(memq bytedecomp-op (eval-when-compile
|
|
|
|
|
(list byte-stack-set2 byte-pushcatch
|
|
|
|
|
byte-pushconditioncase))))
|
2010-11-05 00:32:16 -07:00
|
|
|
|
;; Offset in next 2 bytes.
|
|
|
|
|
(setq bytedecomp-ptr (1+ bytedecomp-ptr))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(+ (aref bytes bytedecomp-ptr)
|
2010-11-05 00:32:16 -07:00
|
|
|
|
(progn (setq bytedecomp-ptr (1+ bytedecomp-ptr))
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
|
(ash (aref bytes bytedecomp-ptr) 8))))
|
2010-11-05 00:32:16 -07:00
|
|
|
|
((and (>= bytedecomp-op byte-listN)
|
2010-12-10 19:13:08 -05:00
|
|
|
|
(<= bytedecomp-op byte-discardN))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(setq bytedecomp-ptr (1+ bytedecomp-ptr)) ;Offset in next byte.
|
|
|
|
|
(aref bytes bytedecomp-ptr))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2011-03-10 09:52:33 -05:00
|
|
|
|
(defvar byte-compile-tag-number)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; This de-compiler is used for inline expansion of compiled functions,
|
|
|
|
|
;; and by the disassembler.
|
|
|
|
|
;;
|
|
|
|
|
;; This list contains numbers, which are pc values,
|
|
|
|
|
;; before each instruction.
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(defun byte-decompile-bytecode (bytes constvec)
|
2007-08-23 19:56:16 +00:00
|
|
|
|
"Turn BYTECODE into lapcode, referring to CONSTVEC."
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(let ((byte-compile-constants nil)
|
|
|
|
|
(byte-compile-variables nil)
|
|
|
|
|
(byte-compile-tag-number 0))
|
|
|
|
|
(byte-decompile-bytecode-1 bytes constvec)))
|
|
|
|
|
|
1992-07-14 02:11:50 +00:00
|
|
|
|
;; As byte-decompile-bytecode, but updates
|
|
|
|
|
;; byte-compile-{constants, variables, tag-number}.
|
1994-07-20 06:04:46 +00:00
|
|
|
|
;; If MAKE-SPLICEABLE is true, then `return' opcodes are replaced
|
1992-07-14 02:11:50 +00:00
|
|
|
|
;; with `goto's destined for the end of the code.
|
1994-07-20 06:04:46 +00:00
|
|
|
|
;; That is for use by the compiler.
|
|
|
|
|
;; If MAKE-SPLICEABLE is nil, we are being called for the disassembler.
|
|
|
|
|
;; In that case, we put a pc value into the list
|
|
|
|
|
;; before each insn (or its label).
|
2011-03-10 09:52:33 -05:00
|
|
|
|
(defun byte-decompile-bytecode-1 (bytes constvec &optional make-spliceable)
|
2011-03-22 20:53:36 -04:00
|
|
|
|
(let ((length (length bytes))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(bytedecomp-ptr 0) optr tags bytedecomp-op offset
|
2017-01-26 00:54:59 +05:30
|
|
|
|
lap tmp last-constant)
|
2010-11-05 00:32:16 -07:00
|
|
|
|
(while (not (= bytedecomp-ptr length))
|
1994-07-20 06:04:46 +00:00
|
|
|
|
(or make-spliceable
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(push bytedecomp-ptr lap))
|
2011-03-22 20:53:36 -04:00
|
|
|
|
(setq bytedecomp-op (aref bytes bytedecomp-ptr)
|
2010-11-05 00:32:16 -07:00
|
|
|
|
optr bytedecomp-ptr
|
2011-03-16 16:08:39 -04:00
|
|
|
|
;; This uses dynamic-scope magic.
|
2011-03-22 20:53:36 -04:00
|
|
|
|
offset (disassemble-offset bytes))
|
2011-04-20 14:28:07 -03:00
|
|
|
|
(let ((opcode (aref byte-code-vector bytedecomp-op)))
|
2012-06-10 09:28:26 -04:00
|
|
|
|
(cl-assert opcode)
|
2011-04-20 14:28:07 -03:00
|
|
|
|
(setq bytedecomp-op opcode))
|
2010-11-05 00:32:16 -07:00
|
|
|
|
(cond ((memq bytedecomp-op byte-goto-ops)
|
2011-03-16 16:08:39 -04:00
|
|
|
|
;; It's a pc.
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(setq offset
|
|
|
|
|
(cdr (or (assq offset tags)
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(let ((new (cons offset (byte-compile-make-tag))))
|
|
|
|
|
(push new tags)
|
|
|
|
|
new)))))
|
2010-11-05 00:32:16 -07:00
|
|
|
|
((cond ((eq bytedecomp-op 'byte-constant2)
|
|
|
|
|
(setq bytedecomp-op 'byte-constant) t)
|
|
|
|
|
((memq bytedecomp-op byte-constref-ops)))
|
1998-05-15 05:49:05 +00:00
|
|
|
|
(setq tmp (if (>= offset (length constvec))
|
|
|
|
|
(list 'out-of-range offset)
|
|
|
|
|
(aref constvec offset))
|
2010-11-05 00:32:16 -07:00
|
|
|
|
offset (if (eq bytedecomp-op 'byte-constant)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(byte-compile-get-constant tmp)
|
|
|
|
|
(or (assq tmp byte-compile-variables)
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(let ((new (list tmp)))
|
|
|
|
|
(push new byte-compile-variables)
|
2017-01-26 00:54:59 +05:30
|
|
|
|
new)))
|
|
|
|
|
last-constant tmp))
|
2010-12-10 19:13:08 -05:00
|
|
|
|
((eq bytedecomp-op 'byte-stack-set2)
|
|
|
|
|
(setq bytedecomp-op 'byte-stack-set))
|
|
|
|
|
((and (eq bytedecomp-op 'byte-discardN) (>= offset #x80))
|
2010-06-13 16:36:17 -04:00
|
|
|
|
;; The top bit of the operand for byte-discardN is a flag,
|
|
|
|
|
;; saying whether the top-of-stack is preserved. In
|
|
|
|
|
;; lapcode, we represent this by using a different opcode
|
|
|
|
|
;; (with the flag removed from the operand).
|
2010-12-10 19:13:08 -05:00
|
|
|
|
(setq bytedecomp-op 'byte-discardN-preserve-tos)
|
2017-01-26 00:54:59 +05:30
|
|
|
|
(setq offset (- offset #x80)))
|
|
|
|
|
((eq bytedecomp-op 'byte-switch)
|
|
|
|
|
(cl-assert (hash-table-p last-constant) nil
|
2018-02-17 09:16:44 -08:00
|
|
|
|
"byte-switch used without preceding hash table")
|
2017-02-05 18:49:24 +05:30
|
|
|
|
;; We cannot use the original hash table referenced in the op,
|
|
|
|
|
;; so we create a copy of it, and replace the addresses with
|
|
|
|
|
;; TAGs.
|
|
|
|
|
(let ((orig-table last-constant))
|
2021-02-12 19:43:41 +01:00
|
|
|
|
(setq last-constant (copy-hash-table last-constant))
|
2017-02-05 18:49:24 +05:30
|
|
|
|
;; Replace all addresses with TAGs.
|
2019-05-21 11:56:14 +02:00
|
|
|
|
(maphash #'(lambda (value offset)
|
|
|
|
|
(let ((match (assq offset tags)))
|
|
|
|
|
(puthash value
|
|
|
|
|
(if match
|
|
|
|
|
(cdr match)
|
|
|
|
|
(let ((tag (byte-compile-make-tag)))
|
|
|
|
|
(push (cons offset tag) tags)
|
|
|
|
|
tag))
|
|
|
|
|
last-constant)))
|
2017-02-05 18:49:24 +05:30
|
|
|
|
last-constant)
|
2017-02-05 18:55:45 +05:30
|
|
|
|
;; Replace the hash table referenced in the lapcode with our
|
|
|
|
|
;; modified one.
|
2017-02-05 18:49:24 +05:30
|
|
|
|
(cl-loop for el in-ref lap
|
2017-02-05 18:55:45 +05:30
|
|
|
|
when (and (listp el) ;; make sure we're at the correct op
|
2017-02-05 18:49:24 +05:30
|
|
|
|
(eq (nth 1 el) 'byte-constant)
|
|
|
|
|
(eq (nth 2 el) orig-table))
|
2017-02-16 09:17:45 -08:00
|
|
|
|
;; Jump tables are never reused, so do this exactly
|
2017-02-13 16:44:06 +05:30
|
|
|
|
;; once.
|
2017-02-05 18:49:24 +05:30
|
|
|
|
do (setf (nth 2 el) last-constant) and return nil))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
;; lap = ( [ (pc . (op . arg)) ]* )
|
2011-03-16 16:08:39 -04:00
|
|
|
|
(push (cons optr (cons bytedecomp-op (or offset 0)))
|
|
|
|
|
lap)
|
2010-11-05 00:32:16 -07:00
|
|
|
|
(setq bytedecomp-ptr (1+ bytedecomp-ptr)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(let ((rest lap))
|
|
|
|
|
(while rest
|
1994-07-20 05:31:29 +00:00
|
|
|
|
(cond ((numberp (car rest)))
|
|
|
|
|
((setq tmp (assq (car (car rest)) tags))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
;; This addr is jumped to.
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(setcdr rest (cons (cons nil (cdr tmp))
|
|
|
|
|
(cdr rest)))
|
|
|
|
|
(setq tags (delq tmp tags))
|
|
|
|
|
(setq rest (cdr rest))))
|
|
|
|
|
(setq rest (cdr rest))))
|
2021-09-18 13:12:41 +02:00
|
|
|
|
(if tags (error "Optimizer error: missed tags %s" tags))
|
2011-03-16 16:08:39 -04:00
|
|
|
|
;; Remove addrs, lap = ( [ (op . arg) | (TAG tagno) ]* )
|
2020-11-12 22:06:47 +01:00
|
|
|
|
(mapcar (lambda (elt)
|
|
|
|
|
(if (numberp elt)
|
|
|
|
|
elt
|
|
|
|
|
(cdr elt)))
|
1994-07-20 05:31:29 +00:00
|
|
|
|
(nreverse lap))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; peephole optimizer
|
|
|
|
|
|
|
|
|
|
(defconst byte-tagref-ops (cons 'TAG byte-goto-ops))
|
|
|
|
|
|
|
|
|
|
(defconst byte-conditional-ops
|
|
|
|
|
'(byte-goto-if-nil byte-goto-if-not-nil byte-goto-if-nil-else-pop
|
|
|
|
|
byte-goto-if-not-nil-else-pop))
|
|
|
|
|
|
|
|
|
|
(defconst byte-after-unbind-ops
|
2022-08-09 10:57:46 +02:00
|
|
|
|
'(byte-constant byte-dup byte-stack-ref byte-stack-set byte-discard
|
2023-02-05 12:14:23 +01:00
|
|
|
|
byte-discardN byte-discardN-preserve-tos
|
1992-07-10 22:06:47 +00:00
|
|
|
|
byte-symbolp byte-consp byte-stringp byte-listp byte-numberp byte-integerp
|
1998-04-17 02:00:04 +00:00
|
|
|
|
byte-eq byte-not
|
2022-08-09 10:57:46 +02:00
|
|
|
|
byte-cons byte-list1 byte-list2 byte-list3 byte-list4 byte-listN
|
1994-08-06 19:25:24 +00:00
|
|
|
|
byte-interactive-p)
|
|
|
|
|
;; How about other side-effect-free-ops? Is it safe to move an
|
|
|
|
|
;; error invocation (such as from nth) out of an unwind-protect?
|
1998-04-17 02:00:04 +00:00
|
|
|
|
;; No, it is not, because the unwind-protect forms can alter
|
|
|
|
|
;; the inside of the object to which nth would apply.
|
|
|
|
|
;; For the same reason, byte-equal was deleted from this list.
|
1994-08-06 19:25:24 +00:00
|
|
|
|
"Byte-codes that can be moved past an unbind.")
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defconst byte-compile-side-effect-and-error-free-ops
|
|
|
|
|
'(byte-constant byte-dup byte-symbolp byte-consp byte-stringp byte-listp
|
|
|
|
|
byte-integerp byte-numberp byte-eq byte-equal byte-not byte-car-safe
|
2022-08-09 10:57:46 +02:00
|
|
|
|
byte-cdr-safe byte-cons byte-list1 byte-list2 byte-list3 byte-list4
|
|
|
|
|
byte-listN byte-point byte-point-max
|
1992-07-10 22:06:47 +00:00
|
|
|
|
byte-point-min byte-following-char byte-preceding-char
|
|
|
|
|
byte-current-column byte-eolp byte-eobp byte-bolp byte-bobp
|
2011-04-01 11:16:50 -04:00
|
|
|
|
byte-current-buffer byte-stack-ref))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
(defconst byte-compile-side-effect-free-ops
|
2020-05-16 17:04:15 -07:00
|
|
|
|
(append
|
1992-07-10 22:06:47 +00:00
|
|
|
|
'(byte-varref byte-nth byte-memq byte-car byte-cdr byte-length byte-aref
|
|
|
|
|
byte-symbol-value byte-get byte-concat2 byte-concat3 byte-sub1 byte-add1
|
|
|
|
|
byte-eqlsign byte-gtr byte-lss byte-leq byte-geq byte-diff byte-negate
|
|
|
|
|
byte-plus byte-max byte-min byte-mult byte-char-after byte-char-syntax
|
|
|
|
|
byte-buffer-substring byte-string= byte-string< byte-nthcdr byte-elt
|
2020-02-21 12:16:20 +01:00
|
|
|
|
byte-member byte-assq byte-quo byte-rem byte-substring)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
byte-compile-side-effect-and-error-free-ops))
|
|
|
|
|
|
2004-04-16 12:51:06 +00:00
|
|
|
|
;; This crock is because of the way DEFVAR_BOOL variables work.
|
|
|
|
|
;; Consider the code
|
|
|
|
|
;;
|
|
|
|
|
;; (defun foo (flag)
|
|
|
|
|
;; (let ((old-pop-ups pop-up-windows)
|
|
|
|
|
;; (pop-up-windows flag))
|
|
|
|
|
;; (cond ((not (eq pop-up-windows old-pop-ups))
|
|
|
|
|
;; (setq old-pop-ups pop-up-windows)
|
|
|
|
|
;; ...))))
|
|
|
|
|
;;
|
|
|
|
|
;; Uncompiled, old-pop-ups will always be set to nil or t, even if FLAG is
|
|
|
|
|
;; something else. But if we optimize
|
|
|
|
|
;;
|
|
|
|
|
;; varref flag
|
|
|
|
|
;; varbind pop-up-windows
|
|
|
|
|
;; varref pop-up-windows
|
|
|
|
|
;; not
|
|
|
|
|
;; to
|
|
|
|
|
;; varref flag
|
|
|
|
|
;; dup
|
|
|
|
|
;; varbind pop-up-windows
|
|
|
|
|
;; not
|
|
|
|
|
;;
|
|
|
|
|
;; we break the program, because it will appear that pop-up-windows and
|
|
|
|
|
;; old-pop-ups are not EQ when really they are. So we have to know what
|
|
|
|
|
;; the BOOL variables are, and not perform this optimization on them.
|
|
|
|
|
|
|
|
|
|
;; The variable `byte-boolean-vars' is now primitive and updated
|
|
|
|
|
;; automatically by DEFVAR_BOOL.
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
2011-03-10 09:52:33 -05:00
|
|
|
|
(defun byte-optimize-lapcode (lap &optional _for-effect)
|
2004-04-16 12:51:06 +00:00
|
|
|
|
"Simple peephole optimizer. LAP is both modified and returned.
|
|
|
|
|
If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
|
2023-02-04 18:58:48 +01:00
|
|
|
|
(let ((side-effect-free (if byte-compile-delete-errors
|
1992-07-10 22:06:47 +00:00
|
|
|
|
byte-compile-side-effect-free-ops
|
2023-02-04 18:58:48 +01:00
|
|
|
|
byte-compile-side-effect-and-error-free-ops))
|
|
|
|
|
(add-depth 0)
|
|
|
|
|
(keep-going 'first-time)
|
|
|
|
|
;; Create a cons cell as head of the list so that removing the first
|
|
|
|
|
;; element does not need special-casing: `setcdr' always works.
|
2023-02-05 11:18:26 +01:00
|
|
|
|
(lap-head (cons nil lap)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(while keep-going
|
2023-02-05 11:18:26 +01:00
|
|
|
|
(byte-compile-log-lap " ---- %s pass"
|
|
|
|
|
(if (eq keep-going 'first-time) "first" "next"))
|
2023-02-04 18:58:48 +01:00
|
|
|
|
(setq keep-going nil)
|
2023-02-05 11:18:26 +01:00
|
|
|
|
(let ((prev lap-head))
|
|
|
|
|
(while (cdr prev)
|
|
|
|
|
(let* ((rest (cdr prev))
|
|
|
|
|
(lap0 (car rest))
|
|
|
|
|
(lap1 (nth 1 rest))
|
|
|
|
|
(lap2 (nth 2 rest)))
|
|
|
|
|
|
|
|
|
|
;; You may notice that sequences like "dup varset discard" are
|
|
|
|
|
;; optimized but sequences like "dup varset TAG1: discard" are not.
|
|
|
|
|
;; You may be tempted to change this; resist that temptation.
|
|
|
|
|
|
|
|
|
|
;; Each clause in this `cond' statement must keep `prev' the
|
|
|
|
|
;; predecessor of the remainder of the list for inspection.
|
|
|
|
|
(cond
|
|
|
|
|
;;
|
|
|
|
|
;; PUSH(K) discard(N) --> <deleted> discard(N-K), N>K
|
|
|
|
|
;; PUSH(K) discard(N) --> <deleted>, N=K
|
|
|
|
|
;; where PUSH(K) is a side-effect-free op such as
|
|
|
|
|
;; const, varref, dup
|
|
|
|
|
;;
|
|
|
|
|
((and (memq (car lap1) '(byte-discard byte-discardN))
|
|
|
|
|
(memq (car lap0) side-effect-free))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
(let* ((pushes (aref byte-stack+-info (symbol-value (car lap0))))
|
|
|
|
|
(pops (if (eq (car lap1) 'byte-discardN) (cdr lap1) 1))
|
|
|
|
|
(net-pops (- pops pushes)))
|
|
|
|
|
(cond ((= net-pops 0)
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t<deleted>"
|
|
|
|
|
lap0 lap1)
|
|
|
|
|
(setcdr prev (cddr rest)))
|
|
|
|
|
((> net-pops 0)
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s %s\t-->\t<deleted> discard(%d)"
|
|
|
|
|
lap0 lap1 net-pops)
|
|
|
|
|
(setcar rest (if (eql net-pops 1)
|
|
|
|
|
(cons 'byte-discard nil)
|
|
|
|
|
(cons 'byte-discardN net-pops)))
|
|
|
|
|
(setcdr rest (cddr rest)))
|
|
|
|
|
(t (error "Optimizer error: too much on the stack")))))
|
|
|
|
|
;;
|
|
|
|
|
;; goto(X) X: --> X:
|
|
|
|
|
;; goto-if-[not-]nil(X) X: --> discard X:
|
|
|
|
|
;;
|
|
|
|
|
((and (memq (car lap0) byte-goto-ops)
|
|
|
|
|
(eq (cdr lap0) lap1))
|
|
|
|
|
(cond ((eq (car lap0) 'byte-goto)
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t<deleted> %s"
|
|
|
|
|
lap0 lap1 lap1)
|
|
|
|
|
(setcdr prev (cdr rest)))
|
|
|
|
|
((memq (car lap0) byte-goto-always-pop-ops)
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\tdiscard %s"
|
|
|
|
|
lap0 lap1 lap1)
|
|
|
|
|
(setcar lap0 'byte-discard)
|
|
|
|
|
(setcdr lap0 0))
|
|
|
|
|
;; goto-*-else-pop(X) cannot occur here because it would
|
|
|
|
|
;; be a depth conflict.
|
|
|
|
|
(t (error "Depth conflict at tag %d" (nth 2 lap0))))
|
|
|
|
|
(setq keep-going t))
|
|
|
|
|
;;
|
|
|
|
|
;; varset-X varref-X --> dup varset-X
|
|
|
|
|
;; varbind-X varref-X --> dup varbind-X
|
|
|
|
|
;; const/dup varset-X varref-X --> const/dup varset-X const/dup
|
|
|
|
|
;; const/dup varbind-X varref-X --> const/dup varbind-X const/dup
|
|
|
|
|
;; The latter two can enable other optimizations.
|
|
|
|
|
;;
|
|
|
|
|
;; For lexical variables, we could do the same
|
|
|
|
|
;; stack-set-X+1 stack-ref-X --> dup stack-set-X+2
|
|
|
|
|
;; but this is a very minor gain, since dup is stack-ref-0,
|
|
|
|
|
;; i.e. it's only better if X>5, and even then it comes
|
|
|
|
|
;; at the cost of an extra stack slot. Let's not bother.
|
|
|
|
|
((and (eq 'byte-varref (car lap2))
|
|
|
|
|
(eq (cdr lap1) (cdr lap2))
|
|
|
|
|
(memq (car lap1) '(byte-varset byte-varbind))
|
|
|
|
|
(let ((tmp (memq (car (cdr lap2)) byte-boolean-vars)))
|
|
|
|
|
(and
|
|
|
|
|
(not (and tmp (not (eq (car lap0) 'byte-constant))))
|
|
|
|
|
(progn
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
(if (memq (car lap0) '(byte-constant byte-dup))
|
|
|
|
|
(let ((tmp (if (or (not tmp)
|
|
|
|
|
(macroexp--const-symbol-p
|
|
|
|
|
(car (cdr lap0))))
|
|
|
|
|
(cdr lap0)
|
|
|
|
|
(byte-compile-get-constant t))))
|
|
|
|
|
(byte-compile-log-lap " %s %s %s\t-->\t%s %s %s"
|
|
|
|
|
lap0 lap1 lap2 lap0 lap1
|
|
|
|
|
(cons (car lap0) tmp))
|
|
|
|
|
(setcar lap2 (car lap0))
|
|
|
|
|
(setcdr lap2 tmp))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\tdup %s"
|
|
|
|
|
lap1 lap2 lap1)
|
|
|
|
|
(setcar lap2 (car lap1))
|
|
|
|
|
(setcar lap1 'byte-dup)
|
|
|
|
|
(setcdr lap1 0)
|
|
|
|
|
;; The stack depth gets locally increased, so we will
|
|
|
|
|
;; increase maxdepth in case depth = maxdepth here.
|
|
|
|
|
;; This can cause the third argument to byte-code to
|
|
|
|
|
;; be larger than necessary.
|
|
|
|
|
(setq add-depth 1))
|
|
|
|
|
t)))))
|
|
|
|
|
;;
|
|
|
|
|
;; dup varset-X discard --> varset-X
|
|
|
|
|
;; dup varbind-X discard --> varbind-X
|
|
|
|
|
;; dup stack-set-X discard --> stack-set-X-1
|
|
|
|
|
;; (the varbind variant can emerge from other optimizations)
|
|
|
|
|
;;
|
|
|
|
|
((and (eq 'byte-dup (car lap0))
|
|
|
|
|
(eq 'byte-discard (car lap2))
|
|
|
|
|
(memq (car lap1) '(byte-varset byte-varbind
|
|
|
|
|
byte-stack-set)))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
(setcdr prev (cdr rest)) ; remove dup
|
|
|
|
|
(setcdr (cdr rest) (cdddr rest)) ; remove discard
|
|
|
|
|
(cond ((not (eq (car lap1) 'byte-stack-set))
|
|
|
|
|
(byte-compile-log-lap " %s %s %s\t-->\t%s"
|
|
|
|
|
lap0 lap1 lap2 lap1))
|
|
|
|
|
((eql (cdr lap1) 1)
|
|
|
|
|
(byte-compile-log-lap " %s %s %s\t-->\t<deleted>"
|
|
|
|
|
lap0 lap1 lap2))
|
|
|
|
|
(t
|
|
|
|
|
(let ((n (1- (cdr lap1))))
|
|
|
|
|
(byte-compile-log-lap " %s %s %s\t-->\t%s"
|
|
|
|
|
lap0 lap1 lap2
|
|
|
|
|
(cons (car lap1) n))
|
|
|
|
|
(setcdr lap1 n)))))
|
|
|
|
|
;;
|
|
|
|
|
;; not goto-X-if-nil --> goto-X-if-non-nil
|
|
|
|
|
;; not goto-X-if-non-nil --> goto-X-if-nil
|
|
|
|
|
;;
|
|
|
|
|
;; it is wrong to do the same thing for the -else-pop variants.
|
|
|
|
|
;;
|
|
|
|
|
((and (eq 'byte-not (car lap0))
|
|
|
|
|
(memq (car lap1) '(byte-goto-if-nil byte-goto-if-not-nil)))
|
|
|
|
|
(let ((not-goto (if (eq (car lap1) 'byte-goto-if-nil)
|
|
|
|
|
'byte-goto-if-not-nil
|
|
|
|
|
'byte-goto-if-nil)))
|
|
|
|
|
(byte-compile-log-lap " not %s\t-->\t%s"
|
|
|
|
|
lap1 (cons not-goto (cdr lap1)))
|
|
|
|
|
(setcar lap1 not-goto)
|
|
|
|
|
(setcdr prev (cdr rest)) ; delete not
|
|
|
|
|
(setq keep-going t)))
|
|
|
|
|
;;
|
|
|
|
|
;; goto-X-if-nil goto-Y X: --> goto-Y-if-non-nil X:
|
|
|
|
|
;; goto-X-if-non-nil goto-Y X: --> goto-Y-if-nil X:
|
|
|
|
|
;;
|
|
|
|
|
;; it is wrong to do the same thing for the -else-pop variants.
|
|
|
|
|
;;
|
|
|
|
|
((and (memq (car lap0)
|
|
|
|
|
'(byte-goto-if-nil byte-goto-if-not-nil)) ; gotoX
|
|
|
|
|
(eq 'byte-goto (car lap1)) ; gotoY
|
|
|
|
|
(eq (cdr lap0) lap2)) ; TAG X
|
|
|
|
|
(let ((inverse (if (eq 'byte-goto-if-nil (car lap0))
|
|
|
|
|
'byte-goto-if-not-nil 'byte-goto-if-nil)))
|
|
|
|
|
(byte-compile-log-lap " %s %s %s\t-->\t%s %s"
|
|
|
|
|
lap0 lap1 lap2
|
|
|
|
|
(cons inverse (cdr lap1)) lap2)
|
|
|
|
|
(setcdr prev (cdr rest))
|
|
|
|
|
(setcar lap1 inverse)
|
|
|
|
|
(setq keep-going t)))
|
|
|
|
|
;;
|
|
|
|
|
;; const goto-if-* --> whatever
|
|
|
|
|
;;
|
|
|
|
|
((and (eq 'byte-constant (car lap0))
|
|
|
|
|
(memq (car lap1) byte-conditional-ops)
|
|
|
|
|
;; Must be an actual constant, not a closure variable.
|
|
|
|
|
(consp (cdr lap0)))
|
|
|
|
|
(cond ((if (memq (car lap1) '(byte-goto-if-nil
|
|
|
|
|
byte-goto-if-nil-else-pop))
|
|
|
|
|
(car (cdr lap0))
|
|
|
|
|
(not (car (cdr lap0))))
|
|
|
|
|
;; Branch not taken.
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t<deleted>"
|
|
|
|
|
lap0 lap1)
|
|
|
|
|
(setcdr prev (cddr rest))) ; delete both
|
|
|
|
|
((memq (car lap1) byte-goto-always-pop-ops)
|
|
|
|
|
;; Always-pop branch taken.
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s"
|
|
|
|
|
lap0 lap1
|
|
|
|
|
(cons 'byte-goto (cdr lap1)))
|
|
|
|
|
(setcdr prev (cdr rest)) ; delete const
|
|
|
|
|
(setcar lap1 'byte-goto))
|
|
|
|
|
(t ; -else-pop branch taken: keep const
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s %s"
|
|
|
|
|
lap0 lap1
|
|
|
|
|
lap0 (cons 'byte-goto (cdr lap1)))
|
2023-02-05 11:56:06 +01:00
|
|
|
|
(setcar lap1 'byte-goto)))
|
2023-02-05 11:18:26 +01:00
|
|
|
|
(setq keep-going t))
|
|
|
|
|
;;
|
|
|
|
|
;; varref-X varref-X --> varref-X dup
|
|
|
|
|
;; varref-X [dup ...] varref-X --> varref-X [dup ...] dup
|
|
|
|
|
;; stackref-X [dup ...] stackref-X+N --> stackref-X [dup ...] dup
|
|
|
|
|
;; We don't optimize the const-X variations on this here,
|
|
|
|
|
;; because that would inhibit some goto optimizations; we
|
|
|
|
|
;; optimize the const-X case after all other optimizations.
|
|
|
|
|
;;
|
|
|
|
|
((and (memq (car lap0) '(byte-varref byte-stack-ref))
|
|
|
|
|
(let ((tmp (cdr rest))
|
|
|
|
|
(tmp2 0))
|
|
|
|
|
(while (eq (car (car tmp)) 'byte-dup)
|
|
|
|
|
(setq tmp2 (1+ tmp2))
|
|
|
|
|
(setq tmp (cdr tmp)))
|
|
|
|
|
(and (eq (if (eq 'byte-stack-ref (car lap0))
|
|
|
|
|
(+ tmp2 1 (cdr lap0))
|
|
|
|
|
(cdr lap0))
|
|
|
|
|
(cdr (car tmp)))
|
|
|
|
|
(eq (car lap0) (car (car tmp)))
|
|
|
|
|
(progn
|
|
|
|
|
(when (memq byte-optimize-log '(t byte))
|
|
|
|
|
(let ((str "")
|
|
|
|
|
(tmp2 (cdr rest)))
|
|
|
|
|
(while (not (eq tmp tmp2))
|
|
|
|
|
(setq tmp2 (cdr tmp2))
|
|
|
|
|
(setq str (concat str " dup")))
|
|
|
|
|
(byte-compile-log-lap " %s%s %s\t-->\t%s%s dup"
|
|
|
|
|
lap0 str lap0 lap0 str)))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
(setcar (car tmp) 'byte-dup)
|
|
|
|
|
(setcdr (car tmp) 0)
|
|
|
|
|
t)))))
|
|
|
|
|
;;
|
|
|
|
|
;; TAG1: TAG2: --> <deleted> TAG2:
|
|
|
|
|
;; (and other references to TAG1 are replaced with TAG2)
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap0) 'TAG)
|
|
|
|
|
(eq (car lap1) 'TAG))
|
|
|
|
|
(byte-compile-log-lap " adjacent tags %d and %d merged"
|
|
|
|
|
(nth 1 lap1) (nth 1 lap0))
|
|
|
|
|
(let ((tmp3 (cdr lap-head)))
|
|
|
|
|
(while (let ((tmp2 (rassq lap0 tmp3)))
|
|
|
|
|
(and tmp2
|
|
|
|
|
(progn
|
|
|
|
|
(setcdr tmp2 lap1)
|
|
|
|
|
(setq tmp3 (cdr (memq tmp2 tmp3)))
|
|
|
|
|
t))))
|
|
|
|
|
(setcdr prev (cdr rest))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
;; replace references to tag in jump tables, if any
|
|
|
|
|
(dolist (table byte-compile-jump-tables)
|
|
|
|
|
(maphash #'(lambda (value tag)
|
|
|
|
|
(when (equal tag lap0)
|
|
|
|
|
(puthash value lap1 table)))
|
|
|
|
|
table))))
|
|
|
|
|
;;
|
|
|
|
|
;; unused-TAG: --> <deleted>
|
|
|
|
|
;;
|
|
|
|
|
((and (eq 'TAG (car lap0))
|
|
|
|
|
(not (rassq lap0 (cdr lap-head)))
|
|
|
|
|
;; make sure this tag isn't used in a jump-table
|
|
|
|
|
(cl-loop for table in byte-compile-jump-tables
|
|
|
|
|
when (member lap0 (hash-table-values table))
|
|
|
|
|
return nil finally return t))
|
|
|
|
|
(byte-compile-log-lap " unused tag %d removed" (nth 1 lap0))
|
|
|
|
|
(setcdr prev (cdr rest))
|
|
|
|
|
(setq keep-going t))
|
|
|
|
|
;;
|
|
|
|
|
;; goto ... --> goto <delete until TAG or end>
|
|
|
|
|
;; return ... --> return <delete until TAG or end>
|
|
|
|
|
;;
|
|
|
|
|
((and (memq (car lap0) '(byte-goto byte-return))
|
|
|
|
|
(not (memq (car lap1) '(TAG nil))))
|
|
|
|
|
(let ((i 0)
|
|
|
|
|
(tmp rest)
|
|
|
|
|
(opt-p (memq byte-optimize-log '(t byte)))
|
|
|
|
|
str deleted)
|
|
|
|
|
(while (and (setq tmp (cdr tmp))
|
|
|
|
|
(not (eq 'TAG (car (car tmp)))))
|
|
|
|
|
(if opt-p (setq deleted (cons (car tmp) deleted)
|
|
|
|
|
str (concat str " %s")
|
|
|
|
|
i (1+ i))))
|
|
|
|
|
(if opt-p
|
|
|
|
|
(let ((tagstr
|
|
|
|
|
(if (eq 'TAG (car (car tmp)))
|
|
|
|
|
(format "%d:" (car (cdr (car tmp))))
|
|
|
|
|
(or (car tmp) ""))))
|
|
|
|
|
(if (< i 6)
|
|
|
|
|
(apply 'byte-compile-log-lap-1
|
|
|
|
|
(concat " %s" str
|
|
|
|
|
" %s\t-->\t%s <deleted> %s")
|
|
|
|
|
lap0
|
|
|
|
|
(nconc (nreverse deleted)
|
|
|
|
|
(list tagstr lap0 tagstr)))
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s <%d unreachable op%s> %s\t-->\t%s <deleted> %s"
|
|
|
|
|
lap0 i (if (= i 1) "" "s")
|
|
|
|
|
tagstr lap0 tagstr))))
|
|
|
|
|
(setcdr rest tmp)
|
|
|
|
|
(setq keep-going t)))
|
|
|
|
|
;;
|
|
|
|
|
;; <safe-op> unbind --> unbind <safe-op>
|
|
|
|
|
;; (this may enable other optimizations.)
|
|
|
|
|
;;
|
|
|
|
|
((and (eq 'byte-unbind (car lap1))
|
|
|
|
|
(memq (car lap0) byte-after-unbind-ops))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s %s" lap0 lap1 lap1 lap0)
|
|
|
|
|
(setcar rest lap1)
|
|
|
|
|
(setcar (cdr rest) lap0)
|
|
|
|
|
(setq keep-going t))
|
|
|
|
|
;;
|
|
|
|
|
;; varbind-X unbind-N --> discard unbind-(N-1)
|
|
|
|
|
;; save-excursion unbind-N --> unbind-(N-1)
|
|
|
|
|
;; save-restriction unbind-N --> unbind-(N-1)
|
|
|
|
|
;; save-current-buffer unbind-N --> unbind-(N-1)
|
|
|
|
|
;;
|
|
|
|
|
((and (eq 'byte-unbind (car lap1))
|
|
|
|
|
(memq (car lap0) '(byte-varbind byte-save-excursion
|
|
|
|
|
byte-save-restriction
|
|
|
|
|
byte-save-current-buffer))
|
|
|
|
|
(< 0 (cdr lap1)))
|
|
|
|
|
(setcdr lap1 (1- (cdr lap1)))
|
|
|
|
|
(when (zerop (cdr lap1))
|
|
|
|
|
(setcdr rest (cddr rest)))
|
|
|
|
|
(if (eq (car lap0) 'byte-varbind)
|
|
|
|
|
(setcar rest (cons 'byte-discard 0))
|
|
|
|
|
(setcdr prev (cddr prev)))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s %s"
|
|
|
|
|
lap0 (cons (car lap1) (1+ (cdr lap1)))
|
|
|
|
|
(if (eq (car lap0) 'byte-varbind)
|
|
|
|
|
(car rest)
|
|
|
|
|
(car (cdr rest)))
|
|
|
|
|
(if (and (/= 0 (cdr lap1))
|
|
|
|
|
(eq (car lap0) 'byte-varbind))
|
|
|
|
|
(car (cdr rest))
|
|
|
|
|
""))
|
|
|
|
|
(setq keep-going t))
|
|
|
|
|
;;
|
|
|
|
|
;; goto*-X ... X: goto-Y --> goto*-Y
|
|
|
|
|
;; goto-X ... X: return --> return
|
|
|
|
|
;;
|
|
|
|
|
((and (memq (car lap0) byte-goto-ops)
|
|
|
|
|
(let ((tmp (nth 1 (memq (cdr lap0) (cdr lap-head)))))
|
|
|
|
|
(and
|
|
|
|
|
(memq (car tmp) '(byte-goto byte-return))
|
|
|
|
|
(or (eq (car lap0) 'byte-goto)
|
|
|
|
|
(eq (car tmp) 'byte-goto))
|
|
|
|
|
(not (eq (cdr tmp) (cdr lap0)))
|
|
|
|
|
(progn
|
|
|
|
|
(byte-compile-log-lap " %s [%s]\t-->\t%s"
|
2023-02-05 12:27:32 +01:00
|
|
|
|
(car lap0) tmp
|
|
|
|
|
(if (eq (car tmp) 'byte-return)
|
|
|
|
|
tmp
|
|
|
|
|
(cons (car lap0) (cdr tmp))))
|
2023-02-05 11:18:26 +01:00
|
|
|
|
(when (eq (car tmp) 'byte-return)
|
|
|
|
|
(setcar lap0 'byte-return))
|
|
|
|
|
(setcdr lap0 (cdr tmp))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
t)))))
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
;; OP goto(X) Y: OP X: -> Y: OP X:
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap1) 'byte-goto)
|
|
|
|
|
(eq (car lap2) 'TAG)
|
|
|
|
|
(let ((lap3 (nth 3 rest)))
|
|
|
|
|
(and (eq (car lap0) (car lap3))
|
|
|
|
|
(eq (cdr lap0) (cdr lap3))
|
|
|
|
|
(eq (cdr lap1) (nth 4 rest)))))
|
|
|
|
|
(byte-compile-log-lap " %s %s %s %s %s\t-->\t%s %s %s"
|
|
|
|
|
lap0 lap1 lap2
|
|
|
|
|
(nth 3 rest) (nth 4 rest)
|
|
|
|
|
lap2 (nth 3 rest) (nth 4 rest))
|
|
|
|
|
(setcdr prev (cddr rest))
|
|
|
|
|
(setq keep-going t))
|
|
|
|
|
|
|
|
|
|
;;
|
2023-02-10 14:38:26 +01:00
|
|
|
|
;; NOEFFECT PRODUCER return --> PRODUCER return
|
|
|
|
|
;; where NOEFFECT lacks effects beyond stack change,
|
|
|
|
|
;; PRODUCER pushes a result without looking at the stack:
|
|
|
|
|
;; const, varref, point etc.
|
2023-02-05 11:18:26 +01:00
|
|
|
|
;;
|
2023-02-10 14:38:26 +01:00
|
|
|
|
((and (eq (car (nth 2 rest)) 'byte-return)
|
|
|
|
|
(memq (car lap1) '( byte-constant byte-varref
|
|
|
|
|
byte-point byte-point-max byte-point-min
|
|
|
|
|
byte-following-char byte-preceding-char
|
|
|
|
|
byte-current-column
|
|
|
|
|
byte-eolp byte-eobp byte-bolp byte-bobp
|
|
|
|
|
byte-current-buffer byte-widen))
|
2023-02-05 11:18:26 +01:00
|
|
|
|
(or (memq (car lap0) '( byte-discard byte-discardN
|
|
|
|
|
byte-discardN-preserve-tos
|
|
|
|
|
byte-stack-set))
|
|
|
|
|
(memq (car lap0) side-effect-free)))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
(setq add-depth 1)
|
|
|
|
|
(setcdr prev (cdr rest))
|
|
|
|
|
(byte-compile-log-lap " %s %s %s\t-->\t%s %s"
|
|
|
|
|
lap0 lap1 (nth 2 rest) lap1 (nth 2 rest)))
|
|
|
|
|
|
2023-02-10 14:38:26 +01:00
|
|
|
|
;;
|
|
|
|
|
;; discardN-preserve-tos OP return --> OP return
|
|
|
|
|
;; dup OP return --> OP return
|
|
|
|
|
;; where OP is 1->1 in stack use, like `not'.
|
|
|
|
|
;;
|
|
|
|
|
;; FIXME: ideally we should run this backwards, so that we could do
|
|
|
|
|
;; discardN-preserve-tos OP1...OPn return -> OP1..OPn return
|
|
|
|
|
;; but that would require a different approach.
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car (nth 2 rest)) 'byte-return)
|
|
|
|
|
(memq (car lap1)
|
|
|
|
|
'( byte-not
|
|
|
|
|
byte-symbolp byte-consp byte-stringp
|
|
|
|
|
byte-listp byte-integerp byte-numberp
|
|
|
|
|
byte-list1
|
|
|
|
|
byte-car byte-cdr byte-car-safe byte-cdr-safe
|
|
|
|
|
byte-length
|
|
|
|
|
byte-add1 byte-sub1 byte-negate byte-nreverse
|
|
|
|
|
;; There are more of these but the list is
|
|
|
|
|
;; getting long and the gain is small.
|
|
|
|
|
))
|
|
|
|
|
(or (memq (car lap0) '(byte-discardN-preserve-tos byte-dup))
|
|
|
|
|
(and (eq (car lap0) 'byte-stack-set)
|
|
|
|
|
(eql (cdr lap0) 1))))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
(setcdr prev (cdr rest)) ; eat lap0
|
|
|
|
|
(byte-compile-log-lap " %s %s %s\t-->\t%s %s"
|
|
|
|
|
lap0 lap1 (nth 2 rest) lap1 (nth 2 rest)))
|
|
|
|
|
|
2023-02-05 11:18:26 +01:00
|
|
|
|
;;
|
|
|
|
|
;; goto-*-else-pop X ... X: goto-if-* --> whatever
|
|
|
|
|
;; goto-*-else-pop X ... X: discard --> whatever
|
|
|
|
|
;;
|
|
|
|
|
((and (memq (car lap0) '(byte-goto-if-nil-else-pop
|
|
|
|
|
byte-goto-if-not-nil-else-pop))
|
|
|
|
|
(let ((tmp (cdr (memq (cdr lap0) (cdr lap-head)))))
|
|
|
|
|
(and
|
|
|
|
|
(memq (caar tmp)
|
|
|
|
|
(eval-when-compile
|
|
|
|
|
(cons 'byte-discard byte-conditional-ops)))
|
|
|
|
|
(not (eq lap0 (car tmp)))
|
|
|
|
|
(let ((tmp2 (car tmp))
|
|
|
|
|
(tmp3 (assq (car lap0)
|
|
|
|
|
'((byte-goto-if-nil-else-pop
|
|
|
|
|
byte-goto-if-nil)
|
|
|
|
|
(byte-goto-if-not-nil-else-pop
|
|
|
|
|
byte-goto-if-not-nil)))))
|
|
|
|
|
(if (memq (car tmp2) tmp3)
|
|
|
|
|
(progn (setcar lap0 (car tmp2))
|
|
|
|
|
(setcdr lap0 (cdr tmp2))
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s-else-pop [%s]\t-->\t%s"
|
|
|
|
|
(car lap0) tmp2 lap0))
|
|
|
|
|
;; Get rid of the -else-pop's and jump one
|
|
|
|
|
;; step further.
|
|
|
|
|
(or (eq 'TAG (car (nth 1 tmp)))
|
|
|
|
|
(setcdr tmp (cons (byte-compile-make-tag)
|
|
|
|
|
(cdr tmp))))
|
|
|
|
|
(byte-compile-log-lap " %s [%s]\t-->\t%s <skip>"
|
|
|
|
|
(car lap0) tmp2 (nth 1 tmp3))
|
|
|
|
|
(setcar lap0 (nth 1 tmp3))
|
|
|
|
|
(setcdr lap0 (nth 1 tmp)))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
t)))))
|
|
|
|
|
;;
|
|
|
|
|
;; const goto-X ... X: goto-if-* --> whatever
|
|
|
|
|
;; const goto-X ... X: discard --> whatever
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap0) 'byte-constant)
|
|
|
|
|
(eq (car lap1) 'byte-goto)
|
|
|
|
|
(let ((tmp (cdr (memq (cdr lap1) (cdr lap-head)))))
|
|
|
|
|
(and
|
|
|
|
|
(memq (caar tmp)
|
|
|
|
|
(eval-when-compile
|
|
|
|
|
(cons 'byte-discard byte-conditional-ops)))
|
|
|
|
|
(not (eq lap1 (car tmp)))
|
|
|
|
|
(let ((tmp2 (car tmp)))
|
|
|
|
|
(cond ((and (consp (cdr lap0))
|
|
|
|
|
(memq (car tmp2)
|
|
|
|
|
(if (null (car (cdr lap0)))
|
|
|
|
|
'(byte-goto-if-nil
|
|
|
|
|
byte-goto-if-nil-else-pop)
|
|
|
|
|
'(byte-goto-if-not-nil
|
|
|
|
|
byte-goto-if-not-nil-else-pop))))
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s goto [%s]\t-->\t%s %s"
|
|
|
|
|
lap0 tmp2 lap0 tmp2)
|
|
|
|
|
(setcar lap1 (car tmp2))
|
|
|
|
|
(setcdr lap1 (cdr tmp2))
|
|
|
|
|
;; Let next step fix the (const,goto-if*) seq.
|
|
|
|
|
(setq keep-going t))
|
|
|
|
|
((or (consp (cdr lap0))
|
|
|
|
|
(eq (car tmp2) 'byte-discard))
|
|
|
|
|
;; Jump one step further
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s goto [%s]\t-->\t<deleted> goto <skip>"
|
|
|
|
|
lap0 tmp2)
|
|
|
|
|
(or (eq 'TAG (car (nth 1 tmp)))
|
|
|
|
|
(setcdr tmp (cons (byte-compile-make-tag)
|
|
|
|
|
(cdr tmp))))
|
|
|
|
|
(setcdr lap1 (car (cdr tmp)))
|
|
|
|
|
(setcdr prev (cdr rest))
|
|
|
|
|
(setq keep-going t))
|
|
|
|
|
(t
|
|
|
|
|
(setq prev (cdr prev))))
|
|
|
|
|
t)))))
|
|
|
|
|
;;
|
|
|
|
|
;; X: varref-Y ... varset-Y goto-X -->
|
|
|
|
|
;; X: varref-Y Z: ... dup varset-Y goto-Z
|
|
|
|
|
;; (varset-X goto-BACK, BACK: varref-X --> copy the varref down.)
|
|
|
|
|
;; (This is so usual for while loops that it is worth handling).
|
|
|
|
|
;;
|
|
|
|
|
;; Here again, we could do it for stack-ref/stack-set, but
|
|
|
|
|
;; that's replacing a stack-ref-Y with a stack-ref-0, which
|
|
|
|
|
;; is a very minor improvement (if any), at the cost of
|
|
|
|
|
;; more stack use and more byte-code. Let's not do it.
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap1) 'byte-varset)
|
|
|
|
|
(eq (car lap2) 'byte-goto)
|
|
|
|
|
(not (memq (cdr lap2) rest)) ;Backwards jump
|
|
|
|
|
(let ((tmp (cdr (memq (cdr lap2) (cdr lap-head)))))
|
|
|
|
|
(and
|
|
|
|
|
(eq (car (car tmp)) 'byte-varref)
|
|
|
|
|
(eq (cdr (car tmp)) (cdr lap1))
|
|
|
|
|
(not (memq (car (cdr lap1)) byte-boolean-vars))
|
|
|
|
|
(let ((newtag (byte-compile-make-tag)))
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s: %s ... %s %s\t-->\t%s: %s %s: ... %s %s %s"
|
|
|
|
|
(nth 1 (cdr lap2)) (car tmp)
|
|
|
|
|
lap1 lap2
|
|
|
|
|
(nth 1 (cdr lap2)) (car tmp)
|
|
|
|
|
(nth 1 newtag) 'byte-dup lap1
|
|
|
|
|
(cons 'byte-goto newtag)
|
|
|
|
|
)
|
|
|
|
|
(setcdr rest (cons (cons 'byte-dup 0) (cdr rest)))
|
|
|
|
|
(setcdr tmp (cons (setcdr lap2 newtag) (cdr tmp)))
|
|
|
|
|
(setq add-depth 1)
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
t)))))
|
|
|
|
|
;;
|
|
|
|
|
;; goto-X Y: ... X: goto-if*-Y --> goto-if-not-*-X+1 Y:
|
|
|
|
|
;; (This can pull the loop test to the end of the loop)
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap0) 'byte-goto)
|
|
|
|
|
(eq (car lap1) 'TAG)
|
|
|
|
|
(let ((tmp (cdr (memq (cdr lap0) (cdr lap-head)))))
|
|
|
|
|
(and
|
|
|
|
|
(eq lap1 (cdar tmp))
|
|
|
|
|
(memq (car (car tmp))
|
|
|
|
|
'( byte-goto byte-goto-if-nil byte-goto-if-not-nil
|
|
|
|
|
byte-goto-if-nil-else-pop))
|
|
|
|
|
(let ((newtag (byte-compile-make-tag)))
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s %s ... %s %s\t-->\t%s ... %s"
|
|
|
|
|
lap0 lap1 (cdr lap0) (car tmp)
|
|
|
|
|
(cons (cdr (assq (car (car tmp))
|
|
|
|
|
'((byte-goto-if-nil
|
|
|
|
|
. byte-goto-if-not-nil)
|
|
|
|
|
(byte-goto-if-not-nil
|
|
|
|
|
. byte-goto-if-nil)
|
|
|
|
|
(byte-goto-if-nil-else-pop
|
|
|
|
|
. byte-goto-if-not-nil-else-pop)
|
|
|
|
|
(byte-goto-if-not-nil-else-pop
|
|
|
|
|
. byte-goto-if-nil-else-pop))))
|
|
|
|
|
newtag)
|
|
|
|
|
newtag)
|
|
|
|
|
(setcdr tmp (cons (setcdr lap0 newtag) (cdr tmp)))
|
|
|
|
|
(when (eq (car (car tmp)) 'byte-goto-if-nil-else-pop)
|
|
|
|
|
;; We can handle this case but not the
|
|
|
|
|
;; -if-not-nil case, because we won't know
|
|
|
|
|
;; which non-nil constant to push.
|
|
|
|
|
(setcdr rest
|
|
|
|
|
(cons (cons 'byte-constant
|
|
|
|
|
(byte-compile-get-constant nil))
|
|
|
|
|
(cdr rest))))
|
|
|
|
|
(setcar lap0 (nth 1 (memq (car (car tmp))
|
|
|
|
|
'(byte-goto-if-nil-else-pop
|
|
|
|
|
byte-goto-if-not-nil
|
|
|
|
|
byte-goto-if-nil
|
|
|
|
|
byte-goto-if-not-nil
|
|
|
|
|
byte-goto byte-goto))))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
t)))))
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
;; discardN-preserve-tos(X) discardN-preserve-tos(Y)
|
|
|
|
|
;; --> discardN-preserve-tos(X+Y)
|
|
|
|
|
;; where stack-set(1) is accepted as discardN-preserve-tos(1)
|
|
|
|
|
;;
|
|
|
|
|
((and (or (eq (car lap0) 'byte-discardN-preserve-tos)
|
|
|
|
|
(and (eq (car lap0) 'byte-stack-set)
|
|
|
|
|
(eql (cdr lap0) 1)))
|
|
|
|
|
(or (eq (car lap1) 'byte-discardN-preserve-tos)
|
|
|
|
|
(and (eq (car lap1) 'byte-stack-set)
|
|
|
|
|
(eql (cdr lap1) 1))))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
(let ((new-op (cons 'byte-discardN-preserve-tos
|
|
|
|
|
;; This happens to work even when either
|
|
|
|
|
;; op is stack-set(1).
|
|
|
|
|
(+ (cdr lap0) (cdr lap1)))))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 new-op)
|
|
|
|
|
(setcar rest new-op)
|
2023-02-05 11:56:06 +01:00
|
|
|
|
(setcdr rest (cddr rest))))
|
2023-02-05 11:18:26 +01:00
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
;; stack-set-M [discard/discardN ...] --> discardN-preserve-tos
|
|
|
|
|
;; stack-set-M [discard/discardN ...] --> discardN
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap0) 'byte-stack-set)
|
|
|
|
|
(memq (car lap1) '(byte-discard byte-discardN))
|
|
|
|
|
(let ((tmp2 (1- (cdr lap0)))
|
|
|
|
|
(tmp3 0)
|
|
|
|
|
(tmp (cdr rest)))
|
|
|
|
|
;; See if enough discard operations follow to expose or
|
|
|
|
|
;; destroy the value stored by the stack-set.
|
|
|
|
|
(while (memq (car (car tmp)) '(byte-discard byte-discardN))
|
|
|
|
|
(setq tmp3
|
|
|
|
|
(+ tmp3 (if (eq (car (car tmp)) 'byte-discard)
|
|
|
|
|
1
|
|
|
|
|
(cdr (car tmp)))))
|
|
|
|
|
(setq tmp (cdr tmp)))
|
|
|
|
|
(and
|
|
|
|
|
(>= tmp3 tmp2)
|
|
|
|
|
(progn
|
|
|
|
|
;; Do the optimization.
|
|
|
|
|
(setcdr prev (cdr rest))
|
|
|
|
|
(setcar lap1
|
|
|
|
|
(if (= tmp2 tmp3)
|
|
|
|
|
;; The value stored is the new TOS, so pop
|
|
|
|
|
;; one more value (to get rid of the old
|
|
|
|
|
;; value) using TOS-preserving discard.
|
|
|
|
|
'byte-discardN-preserve-tos
|
|
|
|
|
;; Otherwise, the value stored is lost,
|
|
|
|
|
;; so just use a normal discard.
|
|
|
|
|
'byte-discardN))
|
|
|
|
|
(setcdr lap1 (1+ tmp3))
|
|
|
|
|
(setcdr (cdr rest) tmp)
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s [discard/discardN]...\t-->\t%s" lap0 lap1)
|
2023-02-05 11:56:06 +01:00
|
|
|
|
(setq keep-going t)
|
2023-02-05 11:18:26 +01:00
|
|
|
|
t
|
|
|
|
|
)))))
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
;; discardN-preserve-tos return --> return
|
|
|
|
|
;; dup return --> return
|
|
|
|
|
;; stack-set(1) return --> return
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap1) 'byte-return)
|
|
|
|
|
(or (memq (car lap0) '(byte-discardN-preserve-tos byte-dup))
|
|
|
|
|
(and (eq (car lap0) 'byte-stack-set)
|
|
|
|
|
(= (cdr lap0) 1))))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
;; The byte-code interpreter will pop the stack for us, so
|
|
|
|
|
;; we can just leave stuff on it.
|
|
|
|
|
(setcdr prev (cdr rest))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 lap1))
|
|
|
|
|
|
2023-02-10 14:38:26 +01:00
|
|
|
|
;;
|
|
|
|
|
;; stack-ref(X) discardN-preserve-tos(Y)
|
|
|
|
|
;; --> discard(Y) stack-ref(X-Y), X≥Y
|
|
|
|
|
;; discard(X) discardN-preserve-tos(Y-X-1), X<Y
|
|
|
|
|
;; where: stack-ref(0) = dup (works both ways)
|
|
|
|
|
;; discard(0) = no-op
|
|
|
|
|
;; discardN-preserve-tos(0) = no-op
|
|
|
|
|
;;
|
|
|
|
|
((and (memq (car lap0) '(byte-stack-ref byte-dup))
|
|
|
|
|
(or (eq (car lap1) 'byte-discardN-preserve-tos)
|
|
|
|
|
(and (eq (car lap1) 'byte-stack-set)
|
|
|
|
|
(eql (cdr lap1) 1)))
|
|
|
|
|
;; Don't apply if immediately preceding a `return',
|
|
|
|
|
;; since there are more effective rules for that case.
|
|
|
|
|
(not (eq (car lap2) 'byte-return)))
|
|
|
|
|
(let ((x (if (eq (car lap0) 'byte-dup) 0 (cdr lap0)))
|
|
|
|
|
(y (cdr lap1)))
|
|
|
|
|
(cl-assert (> y 0))
|
|
|
|
|
(cond
|
|
|
|
|
((>= x y) ; --> discard(Y) stack-ref(X-Y)
|
|
|
|
|
(let ((new0 (if (= y 1)
|
|
|
|
|
(cons 'byte-discard nil)
|
|
|
|
|
(cons 'byte-discardN y)))
|
|
|
|
|
(new1 (if (= x y)
|
|
|
|
|
(cons 'byte-dup nil)
|
|
|
|
|
(cons 'byte-stack-ref (- x y)))))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s %s"
|
|
|
|
|
lap0 lap1 new0 new1)
|
|
|
|
|
(setcar rest new0)
|
|
|
|
|
(setcar (cdr rest) new1)))
|
|
|
|
|
((= x 0) ; --> discardN-preserve-tos(Y-1)
|
|
|
|
|
(setcdr prev (cdr rest)) ; eat lap0
|
|
|
|
|
(if (> y 1)
|
|
|
|
|
(let ((new (cons 'byte-discardN-preserve-tos (- y 1))))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s"
|
|
|
|
|
lap0 lap1 new)
|
|
|
|
|
(setcar (cdr prev) new))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t<deleted>" lap0 lap1)
|
|
|
|
|
(setcdr prev (cddr prev)))) ; eat lap1
|
|
|
|
|
((= y (+ x 1)) ; --> discard(X)
|
|
|
|
|
(setcdr prev (cdr rest)) ; eat lap0
|
|
|
|
|
(let ((new (if (= x 1)
|
|
|
|
|
(cons 'byte-discard nil)
|
|
|
|
|
(cons 'byte-discardN x))))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 new)
|
|
|
|
|
(setcar (cdr prev) new)))
|
|
|
|
|
(t ; --> discard(X) discardN-preserve-tos(Y-X-1)
|
|
|
|
|
(let ((new0 (if (= x 1)
|
|
|
|
|
(cons 'byte-discard nil)
|
|
|
|
|
(cons 'byte-discardN x)))
|
|
|
|
|
(new1 (cons 'byte-discardN-preserve-tos (- y x 1))))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s %s"
|
|
|
|
|
lap0 lap1 new0 new1)
|
|
|
|
|
(setcar rest new0)
|
|
|
|
|
(setcar (cdr rest) new1)))))
|
|
|
|
|
(setq keep-going t))
|
|
|
|
|
|
2023-02-05 11:18:26 +01:00
|
|
|
|
;;
|
|
|
|
|
;; goto-X ... X: discard ==> discard goto-Y ... X: discard Y:
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap0) 'byte-goto)
|
|
|
|
|
(let ((tmp (cdr (memq (cdr lap0) (cdr lap-head)))))
|
|
|
|
|
(and
|
|
|
|
|
tmp
|
|
|
|
|
(or (memq (caar tmp) '(byte-discard byte-discardN))
|
|
|
|
|
;; Make sure we don't hoist a discardN-preserve-tos
|
|
|
|
|
;; that really should be merged or deleted instead.
|
|
|
|
|
(and (eq (caar tmp) 'byte-discardN-preserve-tos)
|
|
|
|
|
(let ((next (cadr tmp)))
|
|
|
|
|
(not (or (memq (car next)
|
|
|
|
|
'(byte-discardN-preserve-tos
|
|
|
|
|
byte-return))
|
|
|
|
|
(and (eq (car next) 'byte-stack-set)
|
|
|
|
|
(eql (cdr next) 1)))))))
|
|
|
|
|
(progn
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" goto-X .. X: \t-->\t%s goto-X.. X: %s Y:"
|
|
|
|
|
(car tmp) (car tmp))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
(let* ((newtag (byte-compile-make-tag))
|
|
|
|
|
;; Make a copy, since we sometimes modify
|
|
|
|
|
;; insts in-place!
|
|
|
|
|
(newdiscard (cons (caar tmp) (cdar tmp)))
|
|
|
|
|
(newjmp (cons (car lap0) newtag)))
|
|
|
|
|
;; Push new tag after the discard.
|
|
|
|
|
(push newtag (cdr tmp))
|
|
|
|
|
(setcar rest newdiscard)
|
|
|
|
|
(push newjmp (cdr rest)))
|
|
|
|
|
t)))))
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
;; const discardN-preserve-tos ==> discardN const
|
|
|
|
|
;; const stack-set(1) ==> discard const
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap0) 'byte-constant)
|
|
|
|
|
(or (eq (car lap1) 'byte-discardN-preserve-tos)
|
|
|
|
|
(and (eq (car lap1) 'byte-stack-set)
|
|
|
|
|
(eql (cdr lap1) 1))))
|
|
|
|
|
(setq keep-going t)
|
|
|
|
|
(let ((newdiscard (if (eql (cdr lap1) 1)
|
2023-01-18 18:36:29 +01:00
|
|
|
|
(cons 'byte-discard nil)
|
2023-02-05 11:18:26 +01:00
|
|
|
|
(cons 'byte-discardN (cdr lap1)))))
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s %s\t-->\t%s %s" lap0 lap1 newdiscard lap0)
|
|
|
|
|
(setf (car rest) newdiscard)
|
2023-02-05 11:56:06 +01:00
|
|
|
|
(setf (cadr rest) lap0)))
|
2023-02-05 11:18:26 +01:00
|
|
|
|
(t
|
|
|
|
|
;; If no rule matched, advance and try again.
|
|
|
|
|
(setq prev (cdr prev))))))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
;; Cleanup stage:
|
|
|
|
|
;; Rebuild byte-compile-constants / byte-compile-variables.
|
|
|
|
|
;; Simple optimizations that would inhibit other optimizations if they
|
|
|
|
|
;; were done in the optimizing loop, and optimizations which there is no
|
2011-02-21 15:12:44 -05:00
|
|
|
|
;; need to do more than once.
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(setq byte-compile-constants nil
|
|
|
|
|
byte-compile-variables nil)
|
2010-06-13 16:36:17 -04:00
|
|
|
|
(byte-compile-log-lap " ---- final pass")
|
2023-02-05 11:18:26 +01:00
|
|
|
|
(let ((prev lap-head))
|
|
|
|
|
(while (cdr prev)
|
|
|
|
|
(let* ((rest (cdr prev))
|
|
|
|
|
(lap0 (car rest))
|
|
|
|
|
(lap1 (nth 1 rest)))
|
|
|
|
|
;; FIXME: Would there ever be a `byte-constant2' op here?
|
|
|
|
|
(if (memq (car lap0) byte-constref-ops)
|
|
|
|
|
(if (memq (car lap0) '(byte-constant byte-constant2))
|
|
|
|
|
(unless (memq (cdr lap0) byte-compile-constants)
|
|
|
|
|
(setq byte-compile-constants (cons (cdr lap0)
|
|
|
|
|
byte-compile-constants)))
|
|
|
|
|
(unless (memq (cdr lap0) byte-compile-variables)
|
|
|
|
|
(setq byte-compile-variables (cons (cdr lap0)
|
|
|
|
|
byte-compile-variables)))))
|
|
|
|
|
(cond
|
|
|
|
|
;;
|
|
|
|
|
;; const-C varset-X const-C --> const-C dup varset-X
|
|
|
|
|
;; const-C varbind-X const-C --> const-C dup varbind-X
|
|
|
|
|
;;
|
|
|
|
|
((and (eq (car lap0) 'byte-constant)
|
|
|
|
|
(eq (car (nth 2 rest)) 'byte-constant)
|
|
|
|
|
(eq (cdr lap0) (cdr (nth 2 rest)))
|
|
|
|
|
(memq (car lap1) '(byte-varbind byte-varset)))
|
|
|
|
|
(byte-compile-log-lap " %s %s %s\t-->\t%s dup %s"
|
|
|
|
|
lap0 lap1 lap0 lap0 lap1)
|
|
|
|
|
(setcar (cdr (cdr rest)) (cons (car lap1) (cdr lap1)))
|
|
|
|
|
(setcar (cdr rest) (cons 'byte-dup 0))
|
|
|
|
|
(setq add-depth 1))
|
|
|
|
|
;;
|
|
|
|
|
;; const-X [dup/const-X ...] --> const-X [dup ...] dup
|
|
|
|
|
;; varref-X [dup/varref-X ...] --> varref-X [dup ...] dup
|
|
|
|
|
;;
|
|
|
|
|
((memq (car lap0) '(byte-constant byte-varref))
|
|
|
|
|
(let ((tmp rest)
|
|
|
|
|
(tmp2 nil))
|
|
|
|
|
(while (progn
|
|
|
|
|
(while (eq 'byte-dup (car (car (setq tmp (cdr tmp))))))
|
|
|
|
|
(and (eq (cdr lap0) (cdr (car tmp)))
|
|
|
|
|
(eq (car lap0) (car (car tmp)))))
|
|
|
|
|
(setcar tmp (cons 'byte-dup 0))
|
|
|
|
|
(setq tmp2 t))
|
|
|
|
|
(if tmp2
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s [dup/%s]...\t-->\t%s dup..." lap0 lap0 lap0)
|
|
|
|
|
(setq prev (cdr prev)))))
|
|
|
|
|
;;
|
|
|
|
|
;; unbind-N unbind-M --> unbind-(N+M)
|
|
|
|
|
;;
|
|
|
|
|
((and (eq 'byte-unbind (car lap0))
|
|
|
|
|
(eq 'byte-unbind (car lap1)))
|
|
|
|
|
(byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1
|
|
|
|
|
(cons 'byte-unbind
|
|
|
|
|
(+ (cdr lap0) (cdr lap1))))
|
|
|
|
|
(setcdr prev (cdr rest))
|
|
|
|
|
(setcdr lap1 (+ (cdr lap1) (cdr lap0))))
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
;; discard/discardN/discardN-preserve-tos-X discard/discardN-Y -->
|
|
|
|
|
;; discardN-(X+Y)
|
|
|
|
|
;;
|
|
|
|
|
((and (memq (car lap0)
|
|
|
|
|
'(byte-discard byte-discardN
|
|
|
|
|
byte-discardN-preserve-tos))
|
|
|
|
|
(memq (car lap1) '(byte-discard byte-discardN)))
|
|
|
|
|
(setcdr prev (cdr rest))
|
|
|
|
|
(byte-compile-log-lap
|
|
|
|
|
" %s %s\t-->\t(discardN %s)"
|
|
|
|
|
lap0 lap1
|
|
|
|
|
(+ (if (eq (car lap0) 'byte-discard) 1 (cdr lap0))
|
|
|
|
|
(if (eq (car lap1) 'byte-discard) 1 (cdr lap1))))
|
|
|
|
|
(setcdr lap1 (+ (if (eq (car lap0) 'byte-discard) 1 (cdr lap0))
|
|
|
|
|
(if (eq (car lap1) 'byte-discard) 1 (cdr lap1))))
|
|
|
|
|
(setcar lap1 'byte-discardN))
|
|
|
|
|
(t
|
|
|
|
|
(setq prev (cdr prev)))))))
|
2023-02-04 18:58:48 +01:00
|
|
|
|
(setq byte-compile-maxdepth (+ byte-compile-maxdepth add-depth))
|
|
|
|
|
(cdr lap-head)))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
1999-08-10 17:13:38 +00:00
|
|
|
|
(provide 'byte-opt)
|
1992-07-10 22:06:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; To avoid "lisp nesting exceeds max-lisp-eval-depth" when this file compiles
|
|
|
|
|
;; itself, compile some of its most used recursive functions (at load time).
|
|
|
|
|
;;
|
|
|
|
|
(eval-when-compile
|
2022-08-14 12:28:37 -04:00
|
|
|
|
(or (compiled-function-p (symbol-function 'byte-optimize-form))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
(assq 'byte-code (symbol-function 'byte-optimize-form))
|
|
|
|
|
(let ((byte-optimize nil)
|
|
|
|
|
(byte-compile-warnings nil))
|
2007-10-12 03:00:05 +00:00
|
|
|
|
(mapc (lambda (x)
|
|
|
|
|
(or noninteractive (message "compiling %s..." x))
|
|
|
|
|
(byte-compile x)
|
|
|
|
|
(or noninteractive (message "compiling %s...done" x)))
|
|
|
|
|
'(byte-optimize-form
|
|
|
|
|
byte-optimize-body
|
Simplify byte-code optimisation of pure functions
Most pure functions need no explicit optimisation; we can do away with
almost all uses of byte-optimize-predicate (now renamed to
byte-optimize-constant-args, since it is not just for predicates).
Also remove some superfluous arity warnings.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-identity, byte-optimize-memq)
(byte-optimize-nth, byte-optimize-nthcdr):
Remove arity warnings and simplify.
* lisp/emacs-lisp/byte-opt.el (<, >, <=, >=, not, null, consp, listp)
(symbolp, stringp, string<, string-lessp, proper-list-p, logand)
(logior, logxor, lognot, car, cdr, car-safe, cdr-safe):
Remove superfluous byte-optimizer property.
(byte-optimize-predicate): Rename to byte-optimize-constant-args.
All uses changed.
2020-07-06 17:38:52 +02:00
|
|
|
|
byte-optimize-constant-args
|
2007-10-12 03:00:05 +00:00
|
|
|
|
byte-optimize-binary-predicate
|
|
|
|
|
;; Inserted some more than necessary, to speed it up.
|
|
|
|
|
byte-optimize-form-code-walker
|
|
|
|
|
byte-optimize-lapcode))))
|
1992-07-10 22:06:47 +00:00
|
|
|
|
nil)
|
1992-07-22 16:55:01 +00:00
|
|
|
|
|
|
|
|
|
;;; byte-opt.el ends here
|