emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: byte compiling defcustom


From: Stefan Monnier
Subject: Re: byte compiling defcustom
Date: Fri, 16 Nov 2007 10:25:13 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.50 (gnu/linux)

>     (defvar foo     (if (featurep 'xemacs) 'bar 'baz) "doc")
>     (defcustom foo1 (if (featurep 'xemacs) 'bar 'baz) "doc")


>     Are compiled to:

>     (defvar foo 'baz (#$ . 543))
>     (custom-declare-variable 'foo1 '(if (featurep 'xemacs) 'bar 'baz) '(#$ . 
> 581))

> The initial value expression for defcustom is saved and gets
> recalculated later in some cases.  So it cannot in general be
> optimized.

He probably meant "compiled" as much as "optimized".
The same holds of keyword arguments to custom-declare-variable, by the way.

> This particular simplification could be done even in defcustom, since
> (featurep 'xemacs) is effectively a constant.  But why bother
> to implement that optimization?  It works fine as it is now.

The patch below implements the desired feature: it byte-compiles the
default-value-expression (first part of the hunk) as well as any
keyword arguments (second part of the hunk).  Notice that the second
part actually simplifies the code.

To me the main benefit is not so much efficiency as better warnings.


        Stefan


PS: While fiddling with it, I discovered that (defvar foo 1 "haha") is
byte compiled into itself (more or less), whereas (defvar foo 1)
gets "open coded" as
(byte-code "..." [current-load-list foo default-boundp set-default 1] 3)
so it won't call Fdefvar and will hence circumvent the check added to
defvar to detect when defvar is used within a `let' binding:

        { /* Check if there is really a global binding rather than just a let
             binding that shadows the global unboundness of the var.  */
          struct specbinding *pdl = specpdl_ptr;
          while (--pdl >= specpdl)
            {
              if (EQ (pdl->symbol, sym) && !pdl->func
                  && EQ (pdl->old_value, Qunbound))
                {
                  message_with_string ("Warning: defvar ignored because %s is 
let-bound",
                                       SYMBOL_NAME (sym), 1);
                  break;
                }
            }
        }

Maybe those defvars shouldn't be open-coded?


--- orig/lisp/emacs-lisp/bytecomp.el
+++ mod/lisp/emacs-lisp/bytecomp.el
@@ -2309,18 +2309,16 @@
   ;;   (byte-compile-nogroup-warn form))
   (when (byte-compile-warning-enabled-p 'free-vars)
     (push (nth 1 (nth 1 form)) byte-compile-special-variables))
+  (when (eq (car-safe (nth 2 form)) 'quote)
+    ;; (nth 2 form) is meant to evaluate to an expression, so if we have the
+    ;; final value already, we can byte-compile it.
+    (setcar (cdr (nth 2 form))
+            (byte-compile-top-level (cadr (nth 2 form)) nil 'file)))
   (let ((tail (nthcdr 4 form)))
     (while tail
-      ;; If there are any (function (lambda ...)) expressions, compile
-      ;; those functions.
-      (if (and (consp (car tail))
-              (eq (car (car tail)) 'function)
-              (consp (nth 1 (car tail))))
-         (setcar tail (byte-compile-lambda (nth 1 (car tail))))
-       ;; Likewise for a bare lambda.
-       (if (and (consp (car tail))
-                (eq (car (car tail)) 'lambda))
-           (setcar tail (byte-compile-lambda (car tail)))))
+      (unless (keywordp (car tail))      ;No point optimizing keywords.
+        ;; Compile the keyword arguments.
+        (setcar tail (byte-compile-top-level (car tail) nil 'file)))
       (setq tail (cdr tail))))
   form)
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]