diff options
| author | Mattias EngdegÄrd | 2019-05-21 11:56:14 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2019-06-19 11:20:58 +0200 |
| commit | 36ab408207d7adf94fd1396922e0df38d746a948 (patch) | |
| tree | 8c0a40db0b370296b32f8681c6aae377072e3ff6 | |
| parent | 2419fa3937f07f8e2e4a79f77fe367a9979cb578 (diff) | |
| download | emacs-36ab408207d7adf94fd1396922e0df38d746a948.tar.gz emacs-36ab408207d7adf94fd1396922e0df38d746a948.zip | |
Compile list member functions in cond to switch (bug#36139)
* lisp/emacs-lisp/bytecomp.el (byte-compile-cond-jump-table-info):
Expand `memq', `memql' and `member' to their corresponding
equality tests.
(byte-compile-cond-jump-table): Cases now have multiple values.
* lisp/emacs-lisp/byte-opt.el (byte-decompile-bytecode-1)
(byte-optimize-lapcode): Don't assume switch hash tables to be injective.
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 21 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 81 |
2 files changed, 65 insertions, 37 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 44cca6136c0..b0aa407c8b4 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -1376,11 +1376,15 @@ | |||
| 1376 | do (setq last-constant (copy-hash-table e)) | 1376 | do (setq last-constant (copy-hash-table e)) |
| 1377 | and return nil) | 1377 | and return nil) |
| 1378 | ;; Replace all addresses with TAGs. | 1378 | ;; Replace all addresses with TAGs. |
| 1379 | (maphash #'(lambda (value tag) | 1379 | (maphash #'(lambda (value offset) |
| 1380 | (let (newtag) | 1380 | (let ((match (assq offset tags))) |
| 1381 | (setq newtag (byte-compile-make-tag)) | 1381 | (puthash value |
| 1382 | (push (cons tag newtag) tags) | 1382 | (if match |
| 1383 | (puthash value newtag last-constant))) | 1383 | (cdr match) |
| 1384 | (let ((tag (byte-compile-make-tag))) | ||
| 1385 | (push (cons offset tag) tags) | ||
| 1386 | tag)) | ||
| 1387 | last-constant))) | ||
| 1384 | last-constant) | 1388 | last-constant) |
| 1385 | ;; Replace the hash table referenced in the lapcode with our | 1389 | ;; Replace the hash table referenced in the lapcode with our |
| 1386 | ;; modified one. | 1390 | ;; modified one. |
| @@ -1722,13 +1726,10 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 1722 | keep-going t) | 1726 | keep-going t) |
| 1723 | ;; replace references to tag in jump tables, if any | 1727 | ;; replace references to tag in jump tables, if any |
| 1724 | (dolist (table byte-compile-jump-tables) | 1728 | (dolist (table byte-compile-jump-tables) |
| 1725 | (catch 'break | ||
| 1726 | (maphash #'(lambda (value tag) | 1729 | (maphash #'(lambda (value tag) |
| 1727 | (when (equal tag lap0) | 1730 | (when (equal tag lap0) |
| 1728 | ;; each tag occurs only once in the jump table | 1731 | (puthash value lap1 table))) |
| 1729 | (puthash value lap1 table) | 1732 | table))) |
| 1730 | (throw 'break nil))) | ||
| 1731 | table)))) | ||
| 1732 | ;; | 1733 | ;; |
| 1733 | ;; unused-TAG: --> <deleted> | 1734 | ;; unused-TAG: --> <deleted> |
| 1734 | ;; | 1735 | ;; |
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 9e3e603c043..ab04c1bf439 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -4139,9 +4139,10 @@ VAR is a variable. | |||
| 4139 | TEST and VAR are the same throughout all conditions. | 4139 | TEST and VAR are the same throughout all conditions. |
| 4140 | VALUE satisfies `macroexp-const-p'. | 4140 | VALUE satisfies `macroexp-const-p'. |
| 4141 | 4141 | ||
| 4142 | Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))" | 4142 | Return a list of the form ((TEST . VAR) ((VALUES BODY) ...))" |
| 4143 | (let ((cases '()) | 4143 | (let ((cases '()) |
| 4144 | (ok t) | 4144 | (ok t) |
| 4145 | (all-keys nil) | ||
| 4145 | prev-var prev-test) | 4146 | prev-var prev-test) |
| 4146 | (and (catch 'break | 4147 | (and (catch 'break |
| 4147 | (dolist (clause (cdr clauses) ok) | 4148 | (dolist (clause (cdr clauses) ok) |
| @@ -4151,23 +4152,46 @@ Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))" | |||
| 4151 | (byte-compile-cond-vars (cadr condition) (cl-caddr condition)))) | 4152 | (byte-compile-cond-vars (cadr condition) (cl-caddr condition)))) |
| 4152 | (obj1 (car-safe vars)) | 4153 | (obj1 (car-safe vars)) |
| 4153 | (obj2 (cdr-safe vars)) | 4154 | (obj2 (cdr-safe vars)) |
| 4154 | (body (cdr-safe clause))) | 4155 | (body (cdr-safe clause)) |
| 4156 | equality) | ||
| 4155 | (unless prev-var | 4157 | (unless prev-var |
| 4156 | (setq prev-var obj1)) | 4158 | (setq prev-var obj1)) |
| 4157 | (unless prev-test | 4159 | (cond |
| 4158 | (setq prev-test test)) | 4160 | ((and obj1 (memq test '(eq eql equal)) |
| 4159 | (if (and obj1 (memq test '(eq eql equal)) | 4161 | (eq obj1 prev-var) |
| 4160 | (eq test prev-test) | 4162 | (or (not prev-test) (eq test prev-test))) |
| 4161 | (eq obj1 prev-var)) | 4163 | (setq prev-test test) |
| 4162 | ;; discard duplicate clauses | 4164 | ;; Discard values already tested for. |
| 4163 | (unless (assoc obj2 cases test) | 4165 | (unless (member obj2 all-keys) |
| 4164 | (push (list obj2 body) cases)) | 4166 | (push obj2 all-keys) |
| 4165 | (if (and (macroexp-const-p condition) condition) | 4167 | (push (list (list obj2) body) cases))) |
| 4166 | (progn (push (list byte-compile--default-val | 4168 | |
| 4167 | (or body `(,condition))) | 4169 | ((and obj1 (memq test '(memq memql member)) |
| 4168 | cases) | 4170 | (eq obj1 prev-var) |
| 4169 | (throw 'break t)) | 4171 | (listp obj2) |
| 4170 | (setq ok nil) | 4172 | ;; Require a non-empty body, since the member function |
| 4173 | ;; value depends on the switch argument. | ||
| 4174 | body | ||
| 4175 | (setq equality (cdr (assq test '((memq . eq) | ||
| 4176 | (memql . eql) | ||
| 4177 | (member . equal))))) | ||
| 4178 | (or (not prev-test) (eq equality prev-test))) | ||
| 4179 | (setq prev-test equality) | ||
| 4180 | (let ((vals nil)) | ||
| 4181 | ;; Discard values already tested for. | ||
| 4182 | (dolist (elem obj2) | ||
| 4183 | (unless (funcall test elem all-keys) | ||
| 4184 | (push elem vals))) | ||
| 4185 | (when vals | ||
| 4186 | (setq all-keys (append vals all-keys)) | ||
| 4187 | (push (list vals body) cases)))) | ||
| 4188 | |||
| 4189 | ((and (macroexp-const-p condition) condition) | ||
| 4190 | (push (list byte-compile--default-val | ||
| 4191 | (or body `(,condition))) | ||
| 4192 | cases) | ||
| 4193 | (throw 'break t)) | ||
| 4194 | (t (setq ok nil) | ||
| 4171 | (throw 'break nil)))))) | 4195 | (throw 'break nil)))))) |
| 4172 | (list (cons prev-test prev-var) (nreverse cases))))) | 4196 | (list (cons prev-test prev-var) (nreverse cases))))) |
| 4173 | 4197 | ||
| @@ -4176,18 +4200,20 @@ Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))" | |||
| 4176 | (test (caar table-info)) | 4200 | (test (caar table-info)) |
| 4177 | (var (cdar table-info)) | 4201 | (var (cdar table-info)) |
| 4178 | (cases (cadr table-info)) | 4202 | (cases (cadr table-info)) |
| 4179 | jump-table test-obj body tag donetag default-tag default-case) | 4203 | jump-table test-objects body tag donetag default-tag default-case) |
| 4180 | (when (and cases (not (= (length cases) 1))) | 4204 | (when (and cases (not (= (length cases) 1))) |
| 4181 | ;; TODO: Once :linear-search is implemented for `make-hash-table' | 4205 | ;; TODO: Once :linear-search is implemented for `make-hash-table' |
| 4182 | ;; set it to `t' for cond forms with a small number of cases. | 4206 | ;; set it to `t' for cond forms with a small number of cases. |
| 4183 | (setq jump-table (make-hash-table | 4207 | (let ((nvalues (apply #'+ (mapcar (lambda (case) (length (car case))) |
| 4184 | :test test | 4208 | cases)))) |
| 4185 | :purecopy t | 4209 | (setq jump-table (make-hash-table |
| 4186 | :size (if (assq byte-compile--default-val cases) | 4210 | :test test |
| 4187 | (1- (length cases)) | 4211 | :purecopy t |
| 4188 | (length cases))) | 4212 | :size (if (assq byte-compile--default-val cases) |
| 4189 | default-tag (byte-compile-make-tag) | 4213 | (1- nvalues) |
| 4190 | donetag (byte-compile-make-tag)) | 4214 | nvalues)))) |
| 4215 | (setq default-tag (byte-compile-make-tag)) | ||
| 4216 | (setq donetag (byte-compile-make-tag)) | ||
| 4191 | ;; The structure of byte-switch code: | 4217 | ;; The structure of byte-switch code: |
| 4192 | ;; | 4218 | ;; |
| 4193 | ;; varref var | 4219 | ;; varref var |
| @@ -4224,10 +4250,11 @@ Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))" | |||
| 4224 | 4250 | ||
| 4225 | (dolist (case cases) | 4251 | (dolist (case cases) |
| 4226 | (setq tag (byte-compile-make-tag) | 4252 | (setq tag (byte-compile-make-tag) |
| 4227 | test-obj (nth 0 case) | 4253 | test-objects (nth 0 case) |
| 4228 | body (nth 1 case)) | 4254 | body (nth 1 case)) |
| 4229 | (byte-compile-out-tag tag) | 4255 | (byte-compile-out-tag tag) |
| 4230 | (puthash test-obj tag jump-table) | 4256 | (dolist (value test-objects) |
| 4257 | (puthash value tag jump-table)) | ||
| 4231 | 4258 | ||
| 4232 | (let ((byte-compile-depth byte-compile-depth) | 4259 | (let ((byte-compile-depth byte-compile-depth) |
| 4233 | (init-depth byte-compile-depth)) | 4260 | (init-depth byte-compile-depth)) |