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