diff options
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 14 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 174 | ||||
| -rw-r--r-- | src/bytecode.c | 16 |
3 files changed, 166 insertions, 38 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 13f885448ae..9412ce3b26d 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -185,6 +185,7 @@ | |||
| 185 | (require 'bytecomp) | 185 | (require 'bytecomp) |
| 186 | (eval-when-compile (require 'cl-lib)) | 186 | (eval-when-compile (require 'cl-lib)) |
| 187 | (require 'macroexp) | 187 | (require 'macroexp) |
| 188 | (require 'subr-x) | ||
| 188 | 189 | ||
| 189 | (defun byte-compile-log-lap-1 (format &rest args) | 190 | (defun byte-compile-log-lap-1 (format &rest args) |
| 190 | ;; Newer byte codes for stack-ref make the slot 0 non-nil again. | 191 | ;; Newer byte codes for stack-ref make the slot 0 non-nil again. |
| @@ -1728,7 +1729,11 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 1728 | ;; unused-TAG: --> <deleted> | 1729 | ;; unused-TAG: --> <deleted> |
| 1729 | ;; | 1730 | ;; |
| 1730 | ((and (eq 'TAG (car lap0)) | 1731 | ((and (eq 'TAG (car lap0)) |
| 1731 | (not (rassq lap0 lap))) | 1732 | (not (rassq lap0 lap)) |
| 1733 | (= (length (cl-loop for table in byte-compile-jump-tables | ||
| 1734 | when (member lap0 (hash-table-values table)) | ||
| 1735 | collect t)) | ||
| 1736 | 0)) | ||
| 1732 | (and (memq byte-optimize-log '(t byte)) | 1737 | (and (memq byte-optimize-log '(t byte)) |
| 1733 | (byte-compile-log " unused tag %d removed" (nth 1 lap0))) | 1738 | (byte-compile-log " unused tag %d removed" (nth 1 lap0))) |
| 1734 | (setq lap (delq lap0 lap) | 1739 | (setq lap (delq lap0 lap) |
| @@ -1736,9 +1741,12 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 1736 | ;; | 1741 | ;; |
| 1737 | ;; goto ... --> goto <delete until TAG or end> | 1742 | ;; goto ... --> goto <delete until TAG or end> |
| 1738 | ;; return ... --> return <delete until TAG or end> | 1743 | ;; return ... --> return <delete until TAG or end> |
| 1739 | ;; | 1744 | ;; (unless a jump-table is being used, where deleting may affect |
| 1745 | ;; other valid case bodies) | ||
| 1746 | ;; | ||
| 1740 | ((and (memq (car lap0) '(byte-goto byte-return)) | 1747 | ((and (memq (car lap0) '(byte-goto byte-return)) |
| 1741 | (not (memq (car lap1) '(TAG nil)))) | 1748 | (not (memq (car lap1) '(TAG nil))) |
| 1749 | (not byte-compile-jump-tables)) | ||
| 1742 | (setq tmp rest) | 1750 | (setq tmp rest) |
| 1743 | (let ((i 0) | 1751 | (let ((i 0) |
| 1744 | (opt-p (memq byte-optimize-log '(t lap))) | 1752 | (opt-p (memq byte-optimize-log '(t lap))) |
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 63be7e208b3..fe91fecd355 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -223,6 +223,11 @@ This includes variable references and calls to functions such as `car'." | |||
| 223 | :group 'bytecomp | 223 | :group 'bytecomp |
| 224 | :type 'boolean) | 224 | :type 'boolean) |
| 225 | 225 | ||
| 226 | (defcustom byte-compile-cond-use-jump-table t | ||
| 227 | "Compile `cond' clauses to a jump table implementation (using a hash-table)." | ||
| 228 | :group 'bytecomp | ||
| 229 | :type 'boolean) | ||
| 230 | |||
| 226 | (defvar byte-compile-dynamic nil | 231 | (defvar byte-compile-dynamic nil |
| 227 | "If non-nil, compile function bodies so they load lazily. | 232 | "If non-nil, compile function bodies so they load lazily. |
| 228 | They are hidden in comments in the compiled file, | 233 | They are hidden in comments in the compiled file, |
| @@ -412,6 +417,8 @@ specify different fields to sort on." | |||
| 412 | (const calls+callers) (const nil))) | 417 | (const calls+callers) (const nil))) |
| 413 | 418 | ||
| 414 | (defvar byte-compile-debug nil) | 419 | (defvar byte-compile-debug nil) |
| 420 | (defvar byte-compile-jump-tables nil | ||
| 421 | "List of all jump tables used during compilation of this form.") | ||
| 415 | (defvar byte-compile-constants nil | 422 | (defvar byte-compile-constants nil |
| 416 | "List of all constants encountered during compilation of this form.") | 423 | "List of all constants encountered during compilation of this form.") |
| 417 | (defvar byte-compile-variables nil | 424 | (defvar byte-compile-variables nil |
| @@ -747,6 +754,8 @@ otherwise pop it") | |||
| 747 | ;; `byte-compile-lapcode'). | 754 | ;; `byte-compile-lapcode'). |
| 748 | (defconst byte-discardN-preserve-tos byte-discardN) | 755 | (defconst byte-discardN-preserve-tos byte-discardN) |
| 749 | 756 | ||
| 757 | (byte-defop 183 -2 byte-switch) | ||
| 758 | |||
| 750 | ;; unused: 182-191 | 759 | ;; unused: 182-191 |
| 751 | 760 | ||
| 752 | (byte-defop 192 1 byte-constant "for reference to a constant") | 761 | (byte-defop 192 1 byte-constant "for reference to a constant") |
| @@ -823,7 +832,7 @@ CONST2 may be evaluated multiple times." | |||
| 823 | op off ; Operation & offset | 832 | op off ; Operation & offset |
| 824 | opcode ; numeric value of OP | 833 | opcode ; numeric value of OP |
| 825 | (bytes '()) ; Put the output bytes here | 834 | (bytes '()) ; Put the output bytes here |
| 826 | (patchlist nil)) ; List of gotos to patch | 835 | (patchlist nil)) ; List of gotos to patch |
| 827 | (dolist (lap-entry lap) | 836 | (dolist (lap-entry lap) |
| 828 | (setq op (car lap-entry) | 837 | (setq op (car lap-entry) |
| 829 | off (cdr lap-entry)) | 838 | off (cdr lap-entry)) |
| @@ -905,6 +914,11 @@ CONST2 may be evaluated multiple times." | |||
| 905 | ;; FIXME: Replace this by some workaround. | 914 | ;; FIXME: Replace this by some workaround. |
| 906 | (if (> (car bytes-tail) 255) (error "Bytecode overflow"))) | 915 | (if (> (car bytes-tail) 255) (error "Bytecode overflow"))) |
| 907 | 916 | ||
| 917 | (dolist (hash-table byte-compile-jump-tables) | ||
| 918 | (cl-loop for k being the hash-keys of hash-table do | ||
| 919 | (let ((tag (cdr (gethash k hash-table)))) | ||
| 920 | (setq pc (car tag)) | ||
| 921 | (puthash k (cons (logand pc 255) (lsh pc -8)) hash-table)))) | ||
| 908 | (apply 'unibyte-string (nreverse bytes)))) | 922 | (apply 'unibyte-string (nreverse bytes)))) |
| 909 | 923 | ||
| 910 | 924 | ||
| @@ -1954,7 +1968,8 @@ With argument ARG, insert value in current buffer after the form." | |||
| 1954 | ;; (edebug-all-defs nil) | 1968 | ;; (edebug-all-defs nil) |
| 1955 | ;; (edebug-all-forms nil) | 1969 | ;; (edebug-all-forms nil) |
| 1956 | ;; Simulate entry to byte-compile-top-level | 1970 | ;; Simulate entry to byte-compile-top-level |
| 1957 | (byte-compile-constants nil) | 1971 | (byte-compile-jump-tables nil) |
| 1972 | (byte-compile-constants nil) | ||
| 1958 | (byte-compile-variables nil) | 1973 | (byte-compile-variables nil) |
| 1959 | (byte-compile-tag-number 0) | 1974 | (byte-compile-tag-number 0) |
| 1960 | (byte-compile-depth 0) | 1975 | (byte-compile-depth 0) |
| @@ -2250,7 +2265,8 @@ list that represents a doc string reference. | |||
| 2250 | byte-compile-variables nil | 2265 | byte-compile-variables nil |
| 2251 | byte-compile-depth 0 | 2266 | byte-compile-depth 0 |
| 2252 | byte-compile-maxdepth 0 | 2267 | byte-compile-maxdepth 0 |
| 2253 | byte-compile-output nil)))) | 2268 | byte-compile-output nil |
| 2269 | byte-compile-jump-tables nil)))) | ||
| 2254 | 2270 | ||
| 2255 | (defvar byte-compile-force-lexical-warnings nil) | 2271 | (defvar byte-compile-force-lexical-warnings nil) |
| 2256 | 2272 | ||
| @@ -2862,7 +2878,8 @@ for symbols generated by the byte compiler itself." | |||
| 2862 | (byte-compile-maxdepth 0) | 2878 | (byte-compile-maxdepth 0) |
| 2863 | (byte-compile--lexical-environment lexenv) | 2879 | (byte-compile--lexical-environment lexenv) |
| 2864 | (byte-compile-reserved-constants (or reserved-csts 0)) | 2880 | (byte-compile-reserved-constants (or reserved-csts 0)) |
| 2865 | (byte-compile-output nil)) | 2881 | (byte-compile-output nil) |
| 2882 | (byte-compile-jump-tables nil)) | ||
| 2866 | (if (memq byte-optimize '(t source)) | 2883 | (if (memq byte-optimize '(t source)) |
| 2867 | (setq form (byte-optimize-form form byte-compile--for-effect))) | 2884 | (setq form (byte-optimize-form form byte-compile--for-effect))) |
| 2868 | (while (and (eq (car-safe form) 'progn) (null (cdr (cdr form)))) | 2885 | (while (and (eq (car-safe form) 'progn) (null (cdr (cdr form)))) |
| @@ -3951,37 +3968,124 @@ that suppresses all warnings during execution of BODY." | |||
| 3951 | (byte-compile-out-tag donetag)))) | 3968 | (byte-compile-out-tag donetag)))) |
| 3952 | (setq byte-compile--for-effect nil)) | 3969 | (setq byte-compile--for-effect nil)) |
| 3953 | 3970 | ||
| 3971 | (defun byte-compile-cond-valid-obj2-p (obj) | ||
| 3972 | (cond | ||
| 3973 | ((symbolp obj) (keywordp obj)) | ||
| 3974 | ((consp obj) (eq (car obj) 'quote)) | ||
| 3975 | (t t))) | ||
| 3976 | |||
| 3977 | (defun byte-compile-cond-vars (obj1 obj2) | ||
| 3978 | (or | ||
| 3979 | (and (symbolp obj1) (byte-compile-cond-valid-obj2-p obj2) (cons obj1 obj2)) | ||
| 3980 | (and (symbolp obj2) (byte-compile-cond-valid-obj2-p obj1) (cons obj2 obj1)))) | ||
| 3981 | |||
| 3982 | (defun byte-compile-cond-jump-table-info (clauses) | ||
| 3983 | (let ((cases '()) | ||
| 3984 | (ok t) | ||
| 3985 | prev-var prev-test) | ||
| 3986 | (and (catch 'break | ||
| 3987 | (dolist (clause (cdr clauses) ok) | ||
| 3988 | (let* ((condition (car clause)) | ||
| 3989 | (test (car-safe condition)) | ||
| 3990 | (vars (when (consp condition) | ||
| 3991 | (byte-compile-cond-vars (cadr condition) (cl-caddr condition)))) | ||
| 3992 | (obj1 (car-safe vars)) | ||
| 3993 | (obj2 (cdr-safe vars)) | ||
| 3994 | (body (cdr-safe clause))) | ||
| 3995 | (unless prev-var | ||
| 3996 | (setq prev-var obj1)) | ||
| 3997 | (unless prev-test | ||
| 3998 | (setq prev-test test)) | ||
| 3999 | (if (and obj1 (memq test '(eq eql equal)) | ||
| 4000 | (consp condition) | ||
| 4001 | (eq test prev-test) | ||
| 4002 | (eq obj1 prev-var)) | ||
| 4003 | (push (list obj2 body) cases) | ||
| 4004 | (if (eq condition t) | ||
| 4005 | (progn (push (list 'default body) cases) | ||
| 4006 | (throw 'break t)) | ||
| 4007 | (setq ok nil) | ||
| 4008 | (throw 'break nil)))))) | ||
| 4009 | (list (cons prev-test prev-var) (nreverse cases))))) | ||
| 4010 | |||
| 4011 | (defun byte-compile-jump-table-add-tag (value tag jump-table) | ||
| 4012 | (setcdr (cdr tag) byte-compile-depth) | ||
| 4013 | (puthash value tag jump-table)) | ||
| 4014 | |||
| 4015 | (defun byte-compile-cond-jump-table (clauses) | ||
| 4016 | (let* ((table-info (byte-compile-cond-jump-table-info clauses)) | ||
| 4017 | (test (caar table-info)) | ||
| 4018 | (var (cdar table-info)) | ||
| 4019 | (cases (cadr table-info)) | ||
| 4020 | jump-table test-obj body tag donetag finaltag finalcase) | ||
| 4021 | (when (and cases (not (= (length cases) 1))) | ||
| 4022 | (setq jump-table (make-hash-table :test test :size (length cases)) | ||
| 4023 | donetag (byte-compile-make-tag)) | ||
| 4024 | (byte-compile-variable-ref var) | ||
| 4025 | (byte-compile-push-constant jump-table) | ||
| 4026 | (byte-compile-out 'byte-switch) | ||
| 4027 | |||
| 4028 | (when (assq 'default cases) | ||
| 4029 | (setq finalcase (cadr (assq 'default cases)) | ||
| 4030 | finaltag (byte-compile-make-tag)) | ||
| 4031 | (setq cases (butlast cases 1)) | ||
| 4032 | (let ((byte-compile-depth byte-compile-depth)) | ||
| 4033 | (byte-compile-goto 'byte-goto finaltag))) | ||
| 4034 | |||
| 4035 | (dolist (case cases) | ||
| 4036 | (setq tag (byte-compile-make-tag) | ||
| 4037 | test-obj (nth 0 case) | ||
| 4038 | body (nth 1 case)) | ||
| 4039 | (byte-compile-out-tag tag) | ||
| 4040 | (byte-compile-jump-table-add-tag test-obj tag jump-table) | ||
| 4041 | |||
| 4042 | (let ((byte-compile-depth byte-compile-depth)) | ||
| 4043 | (byte-compile-maybe-guarded `(,test ,var ,test-obj) | ||
| 4044 | (byte-compile-body body byte-compile--for-effect)) | ||
| 4045 | (byte-compile-goto 'byte-goto donetag)) | ||
| 4046 | (setcdr (cdr donetag) nil)) | ||
| 4047 | |||
| 4048 | (if finalcase | ||
| 4049 | (progn (byte-compile-out-tag finaltag) | ||
| 4050 | (byte-compile-body-do-effect finalcase)) | ||
| 4051 | (byte-compile-push-constant nil)) | ||
| 4052 | (byte-compile-out-tag donetag) | ||
| 4053 | (push jump-table byte-compile-jump-tables)))) | ||
| 4054 | |||
| 3954 | (defun byte-compile-cond (clauses) | 4055 | (defun byte-compile-cond (clauses) |
| 3955 | (let ((donetag (byte-compile-make-tag)) | 4056 | (or (and byte-compile-cond-use-jump-table (byte-compile-cond-jump-table clauses)) |
| 3956 | nexttag clause) | 4057 | (let ((donetag (byte-compile-make-tag)) |
| 3957 | (while (setq clauses (cdr clauses)) | 4058 | nexttag clause) |
| 3958 | (setq clause (car clauses)) | 4059 | (while (setq clauses (cdr clauses)) |
| 3959 | (cond ((or (eq (car clause) t) | 4060 | (setq clause (car clauses)) |
| 3960 | (and (eq (car-safe (car clause)) 'quote) | 4061 | (cond ((or (eq (car clause) t) |
| 3961 | (car-safe (cdr-safe (car clause))))) | 4062 | (and (eq (car-safe (car clause)) 'quote) |
| 3962 | ;; Unconditional clause | 4063 | (car-safe (cdr-safe (car clause))))) |
| 3963 | (setq clause (cons t clause) | 4064 | ;; Unconditional clause |
| 3964 | clauses nil)) | 4065 | (setq clause (cons t clause) |
| 3965 | ((cdr clauses) | 4066 | clauses nil)) |
| 3966 | (byte-compile-form (car clause)) | 4067 | ((cdr clauses) |
| 3967 | (if (null (cdr clause)) | 4068 | (byte-compile-form (car clause)) |
| 3968 | ;; First clause is a singleton. | 4069 | ;; (message "out %s" donetag) |
| 3969 | (byte-compile-goto-if t byte-compile--for-effect donetag) | 4070 | (if (null (cdr clause)) |
| 3970 | (setq nexttag (byte-compile-make-tag)) | 4071 | ;; First clause is a singleton. |
| 3971 | (byte-compile-goto 'byte-goto-if-nil nexttag) | 4072 | (byte-compile-goto-if t byte-compile--for-effect donetag) |
| 3972 | (byte-compile-maybe-guarded (car clause) | 4073 | ;; (message "inside %s" donetag) |
| 3973 | (byte-compile-body (cdr clause) byte-compile--for-effect)) | 4074 | (setq nexttag (byte-compile-make-tag)) |
| 3974 | (byte-compile-goto 'byte-goto donetag) | 4075 | (byte-compile-goto 'byte-goto-if-nil nexttag) |
| 3975 | (byte-compile-out-tag nexttag))))) | 4076 | (byte-compile-maybe-guarded (car clause) |
| 3976 | ;; Last clause | 4077 | (byte-compile-body (cdr clause) byte-compile--for-effect)) |
| 3977 | (let ((guard (car clause))) | 4078 | (byte-compile-goto 'byte-goto donetag) |
| 3978 | (and (cdr clause) (not (eq guard t)) | 4079 | (byte-compile-out-tag nexttag))))) |
| 3979 | (progn (byte-compile-form guard) | 4080 | ;; Last clause |
| 3980 | (byte-compile-goto-if nil byte-compile--for-effect donetag) | 4081 | (let ((guard (car clause))) |
| 3981 | (setq clause (cdr clause)))) | 4082 | (and (cdr clause) (not (eq guard t)) |
| 3982 | (byte-compile-maybe-guarded guard | 4083 | (progn (byte-compile-form guard) |
| 3983 | (byte-compile-body-do-effect clause))) | 4084 | (byte-compile-goto-if nil byte-compile--for-effect donetag) |
| 3984 | (byte-compile-out-tag donetag))) | 4085 | (setq clause (cdr clause)))) |
| 4086 | (byte-compile-maybe-guarded guard | ||
| 4087 | (byte-compile-body-do-effect clause))) | ||
| 4088 | (byte-compile-out-tag donetag)))) | ||
| 3985 | 4089 | ||
| 3986 | (defun byte-compile-and (form) | 4090 | (defun byte-compile-and (form) |
| 3987 | (let ((failtag (byte-compile-make-tag)) | 4091 | (let ((failtag (byte-compile-make-tag)) |
| @@ -4528,7 +4632,7 @@ binding slots have been popped." | |||
| 4528 | (and byte-compile-depth | 4632 | (and byte-compile-depth |
| 4529 | (not (= (cdr (cdr tag)) byte-compile-depth)) | 4633 | (not (= (cdr (cdr tag)) byte-compile-depth)) |
| 4530 | (error "Compiler bug: depth conflict at tag %d" (car (cdr tag)))) | 4634 | (error "Compiler bug: depth conflict at tag %d" (car (cdr tag)))) |
| 4531 | (setq byte-compile-depth (cdr (cdr tag)))) | 4635 | (setq byte-compile-depth (cdr (cdr tag)))) |
| 4532 | (setcdr (cdr tag) byte-compile-depth))) | 4636 | (setcdr (cdr tag) byte-compile-depth))) |
| 4533 | 4637 | ||
| 4534 | (defun byte-compile-goto (opcode tag) | 4638 | (defun byte-compile-goto (opcode tag) |
diff --git a/src/bytecode.c b/src/bytecode.c index a64bc171d14..1695af9cb02 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -267,6 +267,8 @@ DEFINE (Bstack_set, 0262) \ | |||
| 267 | DEFINE (Bstack_set2, 0263) \ | 267 | DEFINE (Bstack_set2, 0263) \ |
| 268 | DEFINE (BdiscardN, 0266) \ | 268 | DEFINE (BdiscardN, 0266) \ |
| 269 | \ | 269 | \ |
| 270 | DEFINE (Bswitch, 0267) \ | ||
| 271 | \ | ||
| 270 | DEFINE (Bconstant, 0300) | 272 | DEFINE (Bconstant, 0300) |
| 271 | 273 | ||
| 272 | enum byte_code_op | 274 | enum byte_code_op |
| @@ -1411,6 +1413,20 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1411 | DISCARD (op); | 1413 | DISCARD (op); |
| 1412 | NEXT; | 1414 | NEXT; |
| 1413 | 1415 | ||
| 1416 | CASE (Bswitch): | ||
| 1417 | { | ||
| 1418 | Lisp_Object jmp_table = POP; | ||
| 1419 | Lisp_Object v1 = POP; | ||
| 1420 | Lisp_Object dest = Fgethash(v1, jmp_table, Qnil); | ||
| 1421 | if (!NILP(dest)) { | ||
| 1422 | int car = XINT(XCAR(dest)); | ||
| 1423 | int cdr = XINT(XCDR(dest)); | ||
| 1424 | op = car + (cdr << 8); /* Simulate FETCH2 */ | ||
| 1425 | goto op_branch; | ||
| 1426 | } | ||
| 1427 | } | ||
| 1428 | NEXT; | ||
| 1429 | |||
| 1414 | CASE_DEFAULT | 1430 | CASE_DEFAULT |
| 1415 | CASE (Bconstant): | 1431 | CASE (Bconstant): |
| 1416 | if (BYTE_CODE_SAFE | 1432 | if (BYTE_CODE_SAFE |