diff options
| author | Stefan Monnier | 2012-06-27 23:31:27 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2012-06-27 23:31:27 -0400 |
| commit | c207708c86ab04f4bb1d78789be0d116e77ba9bb (patch) | |
| tree | ad5da6a992628f001c7c5dce39b847a94575c4c4 | |
| parent | 059e4fb5ed71639f16162e559c9f68f8b5889b9c (diff) | |
| download | emacs-c207708c86ab04f4bb1d78789be0d116e77ba9bb.tar.gz emacs-c207708c86ab04f4bb1d78789be0d116e77ba9bb.zip | |
Make inlining of other-mode interpreted functions work.
* lisp/emacs-lisp/bytecomp.el (byte-compile--refiy-function): New fun.
(byte-compile): Use it to fix compilation of lexical-binding closures.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand): Compile the
function, if needed.
Fixes: debbugs:11799
| -rw-r--r-- | lisp/ChangeLog | 8 | ||||
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 50 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 41 |
3 files changed, 60 insertions, 39 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 566dad73cf0..bb7fca91126 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | 2012-06-28 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | Make inlining of other-mode interpreted functions work (bug#11799). | ||
| 4 | * emacs-lisp/bytecomp.el (byte-compile--refiy-function): New fun. | ||
| 5 | (byte-compile): Use it to fix compilation of lexical-binding closures. | ||
| 6 | * emacs-lisp/byte-opt.el (byte-compile-inline-expand): Compile the | ||
| 7 | function, if needed. | ||
| 8 | |||
| 1 | 2012-06-27 Stefan Monnier <monnier@iro.umontreal.ca> | 9 | 2012-06-27 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 10 | ||
| 3 | * help-mode.el (help-make-xrefs): Don't just withstand | 11 | * help-mode.el (help-make-xrefs): Don't just withstand |
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 92a10dff774..106946b0037 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -266,42 +266,30 @@ | |||
| 266 | ;; (message "Inlining byte-code for %S!" name) | 266 | ;; (message "Inlining byte-code for %S!" name) |
| 267 | ;; The byte-code will be really inlined in byte-compile-unfold-bcf. | 267 | ;; The byte-code will be really inlined in byte-compile-unfold-bcf. |
| 268 | `(,fn ,@(cdr form))) | 268 | `(,fn ,@(cdr form))) |
| 269 | ((or (and `(lambda ,args . ,body) (let env nil)) | 269 | ((or `(lambda . ,_) `(closure . ,_)) |
| 270 | `(closure ,env ,args . ,body)) | ||
| 271 | (if (not (or (eq fn localfn) ;From the same file => same mode. | 270 | (if (not (or (eq fn localfn) ;From the same file => same mode. |
| 272 | (eq (not lexical-binding) (not env)))) ;Same mode. | 271 | (eq (car fn) ;Same mode. |
| 272 | (if lexical-binding 'closure 'lambda)))) | ||
| 273 | ;; While byte-compile-unfold-bcf can inline dynbind byte-code into | 273 | ;; While byte-compile-unfold-bcf can inline dynbind byte-code into |
| 274 | ;; letbind byte-code (or any other combination for that matter), we | 274 | ;; letbind byte-code (or any other combination for that matter), we |
| 275 | ;; can only inline dynbind source into dynbind source or letbind | 275 | ;; can only inline dynbind source into dynbind source or letbind |
| 276 | ;; source into letbind source. | 276 | ;; source into letbind source. |
| 277 | ;; FIXME: we could of course byte-compile the inlined function | 277 | (progn |
| 278 | ;; first, and then inline its byte-code. | 278 | ;; We can of course byte-compile the inlined function |
| 279 | form | 279 | ;; first, and then inline its byte-code. |
| 280 | (let ((renv ())) | 280 | (byte-compile name) |
| 281 | ;; Turn the function's closed vars (if any) into local let bindings. | 281 | `(,(symbol-function name) ,@(cdr form))) |
| 282 | (dolist (binding env) | 282 | (let ((newfn (if (eq fn localfn) |
| 283 | (cond | 283 | ;; If `fn' is from the same file, it has already |
| 284 | ((consp binding) | 284 | ;; been preprocessed! |
| 285 | ;; We check shadowing by the args, so that the `let' can be | 285 | `(function ,fn) |
| 286 | ;; moved within the lambda, which can then be unfolded. | 286 | (byte-compile-preprocess |
| 287 | ;; FIXME: Some of those bindings might be unused in `body'. | 287 | (byte-compile--refiy-function fn))))) |
| 288 | (unless (memq (car binding) args) ;Shadowed. | 288 | (if (eq (car-safe newfn) 'function) |
| 289 | (push `(,(car binding) ',(cdr binding)) renv))) | 289 | (byte-compile-unfold-lambda `(,(cadr newfn) ,@(cdr form))) |
| 290 | ((eq binding t)) | 290 | (byte-compile-log-warning |
| 291 | (t (push `(defvar ,binding) body)))) | 291 | (format "Inlining closure %S failed" name)) |
| 292 | (let ((newfn (if (eq fn localfn) | 292 | form)))) |
| 293 | ;; If `fn' is from the same file, it has already | ||
| 294 | ;; been preprocessed! | ||
| 295 | `(function ,fn) | ||
| 296 | (byte-compile-preprocess | ||
| 297 | (if (null renv) | ||
| 298 | `(lambda ,args ,@body) | ||
| 299 | `(lambda ,args (let ,(nreverse renv) ,@body))))))) | ||
| 300 | (if (eq (car-safe newfn) 'function) | ||
| 301 | (byte-compile-unfold-lambda `(,(cadr newfn) ,@(cdr form))) | ||
| 302 | (byte-compile-log-warning | ||
| 303 | (format "Inlining closure %S failed" name)) | ||
| 304 | form))))) | ||
| 305 | 293 | ||
| 306 | (t ;; Give up on inlining. | 294 | (t ;; Give up on inlining. |
| 307 | form)))) | 295 | form)))) |
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 650faec6bf6..af7bc81fef0 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -2451,7 +2451,26 @@ If QUOTED is non-nil, print with quoting; otherwise, print without quoting." | |||
| 2451 | (- (position-bytes (point)) (point-min) -1) | 2451 | (- (position-bytes (point)) (point-min) -1) |
| 2452 | (goto-char (point-max)))))) | 2452 | (goto-char (point-max)))))) |
| 2453 | 2453 | ||
| 2454 | 2454 | (defun byte-compile--refiy-function (fun) | |
| 2455 | "Return an expression which will evaluate to a function value FUN. | ||
| 2456 | FUN should be either a `lambda' value or a `closure' value." | ||
| 2457 | (pcase-let* (((or (and `(lambda ,args . ,body) (let env nil)) | ||
| 2458 | `(closure ,env ,args . ,body)) fun) | ||
| 2459 | (renv ())) | ||
| 2460 | ;; Turn the function's closed vars (if any) into local let bindings. | ||
| 2461 | (dolist (binding env) | ||
| 2462 | (cond | ||
| 2463 | ((consp binding) | ||
| 2464 | ;; We check shadowing by the args, so that the `let' can be moved | ||
| 2465 | ;; within the lambda, which can then be unfolded. FIXME: Some of those | ||
| 2466 | ;; bindings might be unused in `body'. | ||
| 2467 | (unless (memq (car binding) args) ;Shadowed. | ||
| 2468 | (push `(,(car binding) ',(cdr binding)) renv))) | ||
| 2469 | ((eq binding t)) | ||
| 2470 | (t (push `(defvar ,binding) body)))) | ||
| 2471 | (if (null renv) | ||
| 2472 | `(lambda ,args ,@body) | ||
| 2473 | `(lambda ,args (let ,(nreverse renv) ,@body))))) | ||
| 2455 | 2474 | ||
| 2456 | ;;;###autoload | 2475 | ;;;###autoload |
| 2457 | (defun byte-compile (form) | 2476 | (defun byte-compile (form) |
| @@ -2459,23 +2478,29 @@ If QUOTED is non-nil, print with quoting; otherwise, print without quoting." | |||
| 2459 | If FORM is a lambda or a macro, byte-compile it as a function." | 2478 | If FORM is a lambda or a macro, byte-compile it as a function." |
| 2460 | (displaying-byte-compile-warnings | 2479 | (displaying-byte-compile-warnings |
| 2461 | (byte-compile-close-variables | 2480 | (byte-compile-close-variables |
| 2462 | (let* ((fun (if (symbolp form) | 2481 | (let* ((lexical-binding lexical-binding) |
| 2482 | (fun (if (symbolp form) | ||
| 2463 | (and (fboundp form) (symbol-function form)) | 2483 | (and (fboundp form) (symbol-function form)) |
| 2464 | form)) | 2484 | form)) |
| 2465 | (macro (eq (car-safe fun) 'macro))) | 2485 | (macro (eq (car-safe fun) 'macro))) |
| 2466 | (if macro | 2486 | (if macro |
| 2467 | (setq fun (cdr fun))) | 2487 | (setq fun (cdr fun))) |
| 2468 | (cond ((eq (car-safe fun) 'lambda) | 2488 | (when (symbolp form) |
| 2489 | (unless (memq (car-safe fun) '(closure lambda)) | ||
| 2490 | (error "Don't know how to compile %S" fun)) | ||
| 2491 | (setq fun (byte-compile--refiy-function fun)) | ||
| 2492 | (setq lexical-binding (eq (car fun) 'closure))) | ||
| 2493 | (unless (eq (car-safe fun) 'lambda) | ||
| 2494 | (error "Don't know how to compile %S" fun)) | ||
| 2469 | ;; Expand macros. | 2495 | ;; Expand macros. |
| 2470 | (setq fun (byte-compile-preprocess fun)) | 2496 | (setq fun (byte-compile-preprocess fun)) |
| 2471 | ;; Get rid of the `function' quote added by the `lambda' macro. | 2497 | ;; Get rid of the `function' quote added by the `lambda' macro. |
| 2472 | (if (eq (car-safe fun) 'function) (setq fun (cadr fun))) | 2498 | (if (eq (car-safe fun) 'function) (setq fun (cadr fun))) |
| 2473 | (setq fun (if macro | 2499 | (setq fun (byte-compile-lambda fun)) |
| 2474 | (cons 'macro (byte-compile-lambda fun)) | 2500 | (if macro (push 'macro fun)) |
| 2475 | (byte-compile-lambda fun))) | ||
| 2476 | (if (symbolp form) | 2501 | (if (symbolp form) |
| 2477 | (defalias form fun) | 2502 | (fset form fun) |
| 2478 | fun))))))) | 2503 | fun))))) |
| 2479 | 2504 | ||
| 2480 | (defun byte-compile-sexp (sexp) | 2505 | (defun byte-compile-sexp (sexp) |
| 2481 | "Compile and return SEXP." | 2506 | "Compile and return SEXP." |