Mercurial > hg > xemacs-beta
comparison lisp/bytecomp.el @ 5656:e9c3fe82127d
Co-operate with the byte-optimizer in the bytecomp.el labels implementation.
lisp/ChangeLog addition:
2012-05-05 Aidan Kehoe <kehoea@parhasard.net>
Co-operate with the byte-optimizer in the bytecomp.el labels
implementation, don't work against it.
* byte-optimize.el:
* byte-optimize.el (byte-compile-inline-expand):
Call #'byte-compile-unfold-lambda explicitly here, don't assume
that the byte-optimizer will do it.
* byte-optimize.el (byte-compile-unfold-lambda):
Call #'byte-optimize-body on the body, don't just mapcar
#'byte-optimize-form along it.
* byte-optimize.el (byte-optimize-lambda): New. Optimize a lambda
form.
* byte-optimize.el (byte-optimize-form-code-walker):
Descend lambda expressions, defun, and defmacro, relevant for
lexically-oriented operators like #'labels.
* byte-optimize.el (byte-optimize-body): Only return a non-eq
object if we've actually optimized something
* bytecomp.el (byte-compile-initial-macro-environment):
In the labels implementation, work with the byte optimizer, not
against it; warn when labels are defined but not used,
automatically inline labels that are used only once.
* bytecomp.el (byte-recompile-directory):
No need to wrap #'byte-compile-report-error in a lambda with
#'call-with-condition-handler here.
* bytecomp.el (byte-compile-form):
Don't inline compiled-function objects, they're probably labels.
* bytecomp.el (byte-compile-funcall):
No longer inline lambdas, trust the byte optimizer to have done it
properly, even for labels.
* cl-extra.el (cl-macroexpand-all):
Treat labels established by the byte compiler distinctly from
those established by cl-macs.el.
* cl-macs.el (cl-do-proclaim):
Treat labels established by the byte compiler distinctly from
those established by cl-macs.el.
* gui.el (make-gui-button):
When referring to the #'gui-button-action label, quote it using
function, otherwise there's a warning from the byte compiler.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Sat, 05 May 2012 20:48:24 +0100 |
parents | cc6f0266bc36 |
children | b3a2bff825c8 |
comparison
equal
deleted
inserted
replaced
5655:b7ae5f44b950 | 5656:e9c3fe82127d |
---|---|
520 t 'file)) | 520 t 'file)) |
521 (byte-compile-form `(symbol-value ',gensym) nil)))) | 521 (byte-compile-form `(symbol-value ',gensym) nil)))) |
522 #'(lambda (form &optional read-only) | 522 #'(lambda (form &optional read-only) |
523 (list wrapper form)))) | 523 (list wrapper form)))) |
524 (labels | 524 (labels |
525 . ,#'(lambda (bindings &rest body) | 525 . ,(symbol-macrolet ((wrapper '#:labels)) |
526 (let* ((names (mapcar 'car bindings)) | 526 (labels |
527 (lambdas (mapcar | 527 ((cannot-inline-alist (placeholders lambdas) |
528 (function* | 528 (let ((inline |
529 (lambda ((name . definition)) | 529 ;; What labels should be inline? |
530 (cons 'lambda (cdr (cl-transform-lambda | 530 (remove-if-not |
531 definition name))))) | 531 #'(lambda (placeholder) |
532 bindings)) | 532 (eq 'byte-compile-inline-expand |
533 (placeholders | 533 (get placeholder |
534 (mapcar #'(lambda (lambda) | 534 'byte-optimizer))) |
535 (make-byte-code (second lambda) "\xc0\x87" | 535 placeholders))) |
536 ;; This list is used for | 536 ;; Which of those labels--that should be |
537 ;; the byte-optimize | 537 ;; inline--reference themeselves, or other labels that |
538 ;; property, if the | 538 ;; should be inline? Give a an alist mapping them to |
539 ;; function is to be | 539 ;; their data placeholders. |
540 ;; inlined. See | 540 (mapcan |
541 ;; cl-do-proclaim. | 541 #'(lambda (placeholder lambda) |
542 (vector nil) 1)) | 542 (and |
543 lambdas)) | 543 (eq 'byte-compile-inline-expand |
544 (byte-compile-macro-environment | 544 (get placeholder 'byte-optimizer)) |
545 (pairlis names (mapcar | 545 (block find |
546 #'(lambda (placeholder) | 546 (subst-if nil |
547 `(lambda (&rest cl-labels-args) | 547 #'(lambda (tree) |
548 ;; Be careful not to quote | 548 (if (memq tree inline) |
549 ;; PLACEHOLDER, otherwise | 549 (return-from find t))) |
550 ;; byte-optimize-funcall inlines | 550 lambda) |
551 ;; it. | 551 nil) |
552 (list* 'funcall ,placeholder | 552 `((,placeholder |
553 cl-labels-args))) | 553 . ,(get placeholder |
554 placeholders) | 554 'byte-compile-data-placeholder))))) |
555 byte-compile-macro-environment)) | 555 placeholders lambdas))) |
556 (gensym (gensym))) | 556 (destructure-labels (form for-effect) |
557 (labels | 557 (let* ((names (cadr (cl-pop2 form))) |
558 ((byte-compile-transform-labels (form names lambdas | 558 (lambdas (mapcar #'cadr (cdr (pop form)))) |
559 placeholders) | 559 (placeholders (cadr (pop form))) |
560 (let* ((inline | 560 (cannot-inline-alist (cannot-inline-alist |
561 (mapcan | 561 placeholders lambdas)) |
562 #'(lambda (name placeholder lambda) | 562 (lambdas (sublis cannot-inline-alist |
563 (and | 563 lambdas :test #'eq))) |
564 (eq | 564 ;; Used specially, note the bindings in our callers. |
565 (getf (aref | 565 (setq byte-compile-function-environment |
566 (compiled-function-constants | 566 (pairlis |
567 placeholder) 0) | 567 (mapcar #'cdr cannot-inline-alist) |
568 'byte-optimizer) | 568 (mapcar #'car cannot-inline-alist) |
569 'byte-compile-inline-expand) | 569 (pairlis placeholders lambdas |
570 `(((function ,placeholder) | 570 byte-compile-function-environment))) |
571 ,(byte-compile-lambda lambda name) | 571 (if (memq byte-optimize '(t source)) |
572 (function ,lambda))))) | 572 (setq lambdas |
573 names placeholders lambdas)) | 573 (mapcar #'cadr (mapcar #'byte-optimize-form |
574 (compiled | 574 lambdas)) |
575 (mapcar* #'byte-compile-lambda | 575 form (byte-optimize-body form for-effect))) |
576 (if (not inline) | 576 (values placeholders lambdas names form))) |
577 lambdas | 577 (warn-about-unused-labels (names placeholders) |
578 ;; See further down for the | 578 (when (memq 'unused-vars byte-compile-warnings) |
579 ;; rationale of the sublis calls. | 579 (loop |
580 (sublis (pairlis | 580 for placeholder in placeholders |
581 (mapcar #'cadar inline) | 581 for name in names |
582 (mapcar #'third inline)) | 582 if (eql 0 (+ (get placeholder |
583 (sublis | 583 'byte-compile-label-calls 0) |
584 (pairlis | 584 (get (get placeholder |
585 (mapcar #'car inline) | 585 'byte-compile-data-placeholder |
586 (mapcar #'second inline)) | 586 '#:no-such-data-placeholder) |
587 lambdas :test #'equal) | 587 'byte-compile-label-calls 0))) |
588 :test #'eq)) | 588 do (byte-compile-warn |
589 names)) | 589 "label %s bound but not referenced" name)))) |
590 elt) | 590 (byte-compile-transform-labels (form names lambdas |
591 (mapc #'(lambda (placeholder function) | 591 placeholders) |
592 (nsubst function placeholder compiled | 592 (let ((compiled |
593 :test #'eq | 593 (mapcar* #'byte-compile-lambda lambdas names))) |
594 :descend-structures t)) | 594 (warn-about-unused-labels names placeholders) |
595 placeholders compiled) | 595 (mapc #'(lambda (placeholder function) |
596 (when inline | 596 (nsubst function placeholder compiled |
597 (dolist (triad inline) | 597 :test #'eq |
598 (nsubst (setq elt (elt compiled | 598 :descend-structures t) |
599 (position (cadar triad) | 599 (nsubst function |
600 placeholders))) | 600 (get placeholder |
601 (second triad) compiled :test #'eq | 601 'byte-compile-data-placeholder) |
602 :descend-structures t) | 602 compiled :test #'eq |
603 (setf (second triad) elt)) | 603 :descend-structures t)) |
604 ;; For inlined labels: first, replace uses of | 604 placeholders compiled) |
605 ;; the placeholder in places where it's not an | 605 (sublis (pairlis |
606 ;; evident, explicit funcall (that is, where | 606 placeholders compiled |
607 ;; it is not to be inlined) with the compiled | 607 (pairlis |
608 ;; function: | 608 (mapcar* |
609 (setq form (sublis | 609 #'get placeholders |
610 (pairlis (mapcar #'car inline) | 610 (load-time-value |
611 (mapcar #'second inline)) | 611 (let ((list |
612 form :test #'equal) | 612 (list |
613 ;; Now replace uses of the placeholder | 613 'byte-compile-data-placeholder))) |
614 ;; where it is an evident funcall with the | 614 (nconc list list)))) |
615 ;; lambda, quoted as a function, to allow | 615 compiled)) |
616 ;; byte-optimize-funcall to do its | 616 form :test #'eq)))) |
617 ;; thing. Note that the lambdas still have | 617 (put wrapper 'byte-compile |
618 ;; the placeholders, so there's no risk | 618 #'(lambda (form) |
619 ;; of recursive inlining. | 619 (let ((byte-compile-function-environment |
620 form (sublis (pairlis | 620 byte-compile-function-environment)) |
621 (mapcar #'cadar inline) | 621 (multiple-value-bind |
622 (mapcar #'third inline)) | 622 (placeholders lambdas names form) |
623 form :test #'eq))) | 623 (destructure-labels form for-effect) |
624 (sublis (pairlis placeholders compiled) form | 624 (byte-compile-body-do-effect |
625 :test #'eq)))) | 625 (byte-compile-transform-labels form names |
626 (put gensym 'byte-compile | 626 lambdas |
627 #'(lambda (form) | 627 placeholders)))))) |
628 (let* ((names (cadr (cl-pop2 form))) | 628 (put wrapper 'byte-hunk-handler |
629 (lambdas (mapcar #'cadr (cdr (pop form)))) | 629 #'(lambda (form) |
630 (placeholders (cadr (pop form)))) | 630 (let ((byte-compile-function-environment |
631 (byte-compile-body-do-effect | 631 byte-compile-function-environment)) |
632 (byte-compile-transform-labels form names | 632 (multiple-value-bind |
633 lambdas | 633 (placeholders lambdas names form) |
634 placeholders))))) | 634 (destructure-labels form t) |
635 (put gensym 'byte-hunk-handler | 635 (byte-compile-file-form |
636 #'(lambda (form) | 636 (cons 'progn |
637 (let* ((names (cadr (cl-pop2 form))) | 637 (byte-compile-transform-labels |
638 (lambdas (mapcar #'cadr (cdr (pop form)))) | 638 form names lambdas placeholders))))))) |
639 (placeholders (cadr (pop form)))) | 639 (put wrapper 'cl-compiler-macro |
640 (byte-compile-file-form | 640 ;; This is only used when optimizing code. |
641 (cons 'progn | 641 #'(lambda (form &rest ignore) |
642 (byte-compile-transform-labels | 642 (let ((byte-compile-function-environment |
643 form names lambdas placeholders)))))) | 643 byte-compile-function-environment) |
644 (setq body | 644 byte-optimize-form retry) |
645 (cl-macroexpand-all `(,gensym ',names (list ,@lambdas) | 645 (multiple-value-bind |
646 ',placeholders ,@body) | 646 (placeholders lambdas) |
647 byte-compile-macro-environment)) | 647 (destructure-labels form for-effect) |
648 (if (position 'lambda (mapcar #'(lambda (object) | 648 ;; Optimize most of the form, in passing |
649 (car-safe (cdr-safe | 649 ;; expanding macros. |
650 object))) | 650 (setq byte-optimize-form |
651 (cdr (third body))) | 651 (mapcar #'byte-optimize-form |
652 :key #'car-safe :test-not #'eq) | 652 (list* (nth 1 form) `(list ,@lambdas) |
653 ;; #'lexical-let has worked its magic, not all the | 653 (cdddr form)))) |
654 ;; lambdas are lambdas. Give up on pre-compiling the | 654 ;; It may be reasonable to inline any labels |
655 ;; labels. | 655 ;; used only once. |
656 (setq names (mapcar #'copy-symbol names) | 656 (dolist (placeholder placeholders) |
657 lambdas (cdr (third body)) | 657 (and |
658 body (sublis (pairlis placeholders names) | 658 (not (eq 'byte-compile-inline-expand |
659 (nthcdr 4 body) :test #'eq) | 659 (get placeholder 'byte-optimizer))) |
660 lambdas (sublis (pairlis placeholders names) | 660 (eql 0 (get (get placeholder |
661 lambdas :test #'eq) | 661 'byte-compile-data-placeholder |
662 body (cl-macroexpand-all | 662 '#:no-such-data-placeholder) |
663 `(lexical-let | 663 'byte-compile-label-calls 0)) |
664 ,names | 664 (eql 1 (get placeholder |
665 (setf ,@(mapcan #'list names lambdas)) | 665 'byte-compile-label-calls 0)) |
666 ,@body) | 666 (progn |
667 byte-compile-macro-environment)) | 667 (byte-compile-log |
668 body))))) | 668 "label %s is used only once, inlining it" |
669 placeholder) | |
670 (setq retry t) | |
671 (cl-do-proclaim `(inline ,placeholder) t)))) | |
672 (when retry | |
673 (multiple-value-setq | |
674 (placeholders lambdas) | |
675 (destructure-labels form for-effect)) | |
676 (setq byte-optimize-form | |
677 (mapcar #'byte-optimize-form | |
678 (list* (nth 1 form) | |
679 `(list ,@lambdas) | |
680 (cdddr form))))) | |
681 (if (equal (cdr form) byte-optimize-form) | |
682 form | |
683 (cons (car form) byte-optimize-form))))))) | |
684 #'(lambda (bindings &rest body) | |
685 (let* ((names (mapcar 'car bindings)) | |
686 (lambdas (mapcar | |
687 (function* | |
688 (lambda ((name . definition)) | |
689 `#'(lambda ,@(cdr (cl-transform-lambda | |
690 definition name))))) | |
691 bindings)) | |
692 (placeholders (mapcar #'copy-symbol names)) | |
693 (byte-compile-macro-environment | |
694 (pairlis names | |
695 (mapcar | |
696 #'(lambda (placeholder) | |
697 `(lambda (&rest byte-compile-labels-args) | |
698 (put | |
699 ',placeholder | |
700 'byte-compile-label-calls | |
701 (1+ (get ',placeholder | |
702 'byte-compile-label-calls | |
703 0))) | |
704 (cons ',placeholder | |
705 byte-compile-labels-args))) | |
706 placeholders) | |
707 byte-compile-macro-environment))) | |
708 ;; Tell the macroexpansion code what symbol to use when | |
709 ;; expanding #'FUNCTION-NAME: | |
710 (mapc #'put placeholders | |
711 (load-time-value | |
712 (let ((list (list 'byte-compile-data-placeholder))) | |
713 (nconc list list))) | |
714 (mapcar #'copy-symbol names)) | |
715 (setq body | |
716 (cl-macroexpand-all | |
717 `(,wrapper ',names (list ,@lambdas) ',placeholders | |
718 ,@body) | |
719 byte-compile-macro-environment)) | |
720 (if (position 'lambda (mapcar #'(lambda (object) | |
721 (car-safe (cdr-safe | |
722 object))) | |
723 (cdr (third body))) | |
724 :key #'car-safe :test-not #'eq) | |
725 ;; #'lexical-let has worked its magic, not all the | |
726 ;; lambdas are lambdas. Give up on pre-compiling the | |
727 ;; labels. | |
728 (setq names (mapcar #'copy-symbol names) | |
729 lambdas (cdr (third body)) | |
730 body (sublis (pairlis placeholders names) | |
731 (nthcdr 4 body) :test #'eq) | |
732 lambdas (sublis (pairlis placeholders names) | |
733 lambdas :test #'eq) | |
734 body (cl-macroexpand-all | |
735 `(lexical-let | |
736 ,names | |
737 (setf ,@(mapcan #'list names lambdas)) | |
738 ,@body) | |
739 byte-compile-macro-environment)) | |
740 body))))) | |
669 (flet . | 741 (flet . |
670 ,#'(lambda (bindings &rest body) | 742 ,#'(lambda (bindings &rest body) |
671 (let* ((names (mapcar 'car bindings)) | 743 (let* ((names (mapcar 'car bindings)) |
672 (lambdas (mapcar | 744 (lambdas (mapcar |
673 (function* | 745 (function* |
1640 byte-compile-warnings-beginning | 1712 byte-compile-warnings-beginning |
1641 (point-max byte-compile-log-buffer)))) | 1713 (point-max byte-compile-log-buffer)))) |
1642 | 1714 |
1643 (unwind-protect | 1715 (unwind-protect |
1644 (call-with-condition-handler | 1716 (call-with-condition-handler |
1645 #'(lambda (error-info) | 1717 #'byte-compile-report-error |
1646 (byte-compile-report-error error-info)) | |
1647 #'(lambda () | 1718 #'(lambda () |
1648 (progn ,@body))) | 1719 (progn ,@body))) |
1649 ;; Always set point in log to start of interesting output. | 1720 ;; Always set point in log to start of interesting output. |
1650 (with-current-buffer byte-compile-log-buffer | 1721 (with-current-buffer byte-compile-log-buffer |
1651 (let ((show-begin | 1722 (let ((show-begin |
3008 (if handler | 3079 (if handler |
3009 (funcall handler form) | 3080 (funcall handler form) |
3010 (if (memq 'callargs byte-compile-warnings) | 3081 (if (memq 'callargs byte-compile-warnings) |
3011 (byte-compile-callargs-warn form)) | 3082 (byte-compile-callargs-warn form)) |
3012 (byte-compile-normal-call form)))) | 3083 (byte-compile-normal-call form)))) |
3013 ((and (or (compiled-function-p (car form)) | 3084 ((and (eq (car-safe (car form)) 'lambda) |
3014 (eq (car-safe (car form)) 'lambda)) | |
3015 ;; if the form comes out the same way it went in, that's | 3085 ;; if the form comes out the same way it went in, that's |
3016 ;; because it was malformed, and we couldn't unfold it. | 3086 ;; because it was malformed, and we couldn't unfold it. |
3017 (not (eq form (setq form (byte-compile-unfold-lambda form))))) | 3087 (not (eq form (setq form (byte-compile-unfold-lambda form))))) |
3018 (byte-compile-form form for-effect) | 3088 (byte-compile-form form for-effect) |
3019 (setq for-effect nil)) | 3089 (setq for-effect nil)) |
3046 ;; cl-parsing-keywords macro, but the below list does. | 3116 ;; cl-parsing-keywords macro, but the below list does. |
3047 | 3117 |
3048 (map nil | 3118 (map nil |
3049 (function* | 3119 (function* |
3050 (lambda ((function . nargs)) | 3120 (lambda ((function . nargs)) |
3051 ;; Document that the car of OBJECT, a symbol, describes a function | 3121 ;; Document that FUNCTION, a symbol, describes a function taking |
3052 ;; taking keyword arguments from the argument index described by | 3122 ;; keyword arguments from the argument index described by NARGS. |
3053 ;; the cdr of OBJECT. | |
3054 (put function 'byte-compile-keyword-start nargs))) | 3123 (put function 'byte-compile-keyword-start nargs))) |
3055 '((adjoin . 3) (assoc* . 3) (assoc-if . 3) (assoc-if-not . 3) | 3124 '((adjoin . 3) (assoc* . 3) (assoc-if . 3) (assoc-if-not . 3) |
3056 (count . 3) (count-if . 3) (count-if-not . 3) (define-behavior . 3) | 3125 (count . 3) (count-if . 3) (count-if-not . 3) (define-behavior . 3) |
3057 (define-behavior-group . 2) (delete* . 3) (delete-duplicates . 2) | 3126 (define-behavior-group . 2) (delete* . 3) (delete-duplicates . 2) |
3058 (delete-if . 3) (delete-if-not . 3) (fill . 3) (find . 3) (find-if . 3) | 3127 (delete-if . 3) (delete-if-not . 3) (fill . 3) (find . 3) (find-if . 3) |
4173 (defun byte-compile-funcall (form) | 4242 (defun byte-compile-funcall (form) |
4174 (if (and (memq 'callargs byte-compile-warnings) | 4243 (if (and (memq 'callargs byte-compile-warnings) |
4175 (byte-compile-constp (second form))) | 4244 (byte-compile-constp (second form))) |
4176 (byte-compile-callargs-warn (cons (cl-const-expr-val (second form)) | 4245 (byte-compile-callargs-warn (cons (cl-const-expr-val (second form)) |
4177 (nthcdr 2 form)))) | 4246 (nthcdr 2 form)))) |
4178 (if (and byte-optimize | 4247 (mapc 'byte-compile-form (cdr form)) |
4179 (eq 'function (car-safe (cadr form))) | 4248 (byte-compile-out 'byte-call (length (cdr (cdr form))))) |
4180 (eq 'lambda (car-safe (cadadr form))) | |
4181 (or | |
4182 (not (eq (setq form (cons (cadadr form) (cddr form))) | |
4183 (setq form (byte-compile-unfold-lambda form)))) | |
4184 (prog1 nil (setq form `(funcall #',(car form) ,@(cdr form)))))) | |
4185 ;; The byte-compile part of the #'labels implementation, above, | |
4186 ;; happens after macroexpansion and after the source optimizer has | |
4187 ;; done its thing. When labels are to be made inline we can have code | |
4188 ;; that looks like (funcall #'(lambda ...) ...), when the code that | |
4189 ;; the optimizer saw looked like (funcall #<compiled-function ...> | |
4190 ;; ...). | |
4191 ;; | |
4192 ;; So, the optimizer doesn't have the opportunity to transform the | |
4193 ;; former to (let (...) ...), and it's reasonable to do that here (since | |
4194 ;; the labels implementation doesn't change other code that would need | |
4195 ;; running through the optimizer; the lambda itself has already been | |
4196 ;; through the optimizer). | |
4197 ;; | |
4198 ;; Equally reasonable, and conceptually a bit clearer, would be to do | |
4199 ;; the transformation to (funcall #'(lambda ...) ...) in the | |
4200 ;; byte-optimizer, breaking most of the #'sublis calls out of the | |
4201 ;; byte-compile method. | |
4202 (byte-compile-form form) | |
4203 (mapc 'byte-compile-form (cdr form)) | |
4204 (byte-compile-out 'byte-call (length (cdr (cdr form)))))) | |
4205 | |
4206 | 4249 |
4207 (defun byte-compile-let (form) | 4250 (defun byte-compile-let (form) |
4208 ;; First compute the binding values in the old scope. | 4251 ;; First compute the binding values in the old scope. |
4209 (let ((varlist (car (cdr form)))) | 4252 (let ((varlist (car (cdr form)))) |
4210 (while varlist | 4253 (while varlist |