428
+ − 1 ;;; byte-optimize.el --- the optimization passes of the emacs-lisp byte compiler.
+ − 2
+ − 3 ;;; Copyright (c) 1991, 1994 Free Software Foundation, Inc.
+ − 4
446
+ − 5 ;; Authors: Jamie Zawinski <jwz@jwz.org>
+ − 6 ;; Hallvard Furuseth <hbf@ulrik.uio.no>
+ − 7 ;; Martin Buchholz <martin@xemacs.org>
428
+ − 8 ;; Keywords: internal
+ − 9
+ − 10 ;; This file is part of XEmacs.
+ − 11
+ − 12 ;; XEmacs is free software; you can redistribute it and/or modify it
+ − 13 ;; under the terms of the GNU General Public License as published by
+ − 14 ;; the Free Software Foundation; either version 2, or (at your option)
+ − 15 ;; any later version.
+ − 16
+ − 17 ;; XEmacs is distributed in the hope that it will be useful, but
+ − 18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
+ − 19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ − 20 ;; General Public License for more details.
+ − 21
+ − 22 ;; You should have received a copy of the GNU General Public License
440
+ − 23 ;; along with XEmacs; see the file COPYING. If not, write to the
428
+ − 24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ − 25 ;; Boston, MA 02111-1307, USA.
+ − 26
444
+ − 27 ;;; Synched up with: FSF 20.7.
428
+ − 28
+ − 29 ;;; Commentary:
+ − 30
+ − 31 ;; ========================================================================
+ − 32 ;; "No matter how hard you try, you can't make a racehorse out of a pig.
+ − 33 ;; You can, however, make a faster pig."
+ − 34 ;;
+ − 35 ;; Or, to put it another way, the emacs byte compiler is a VW Bug. This code
440
+ − 36 ;; makes it be a VW Bug with fuel injection and a turbocharger... You're
428
+ − 37 ;; still not going to make it go faster than 70 mph, but it might be easier
+ − 38 ;; to get it there.
+ − 39 ;;
+ − 40
+ − 41 ;; TO DO:
+ − 42 ;;
+ − 43 ;; (apply #'(lambda (x &rest y) ...) 1 (foo))
+ − 44 ;;
+ − 45 ;; maintain a list of functions known not to access any global variables
+ − 46 ;; (actually, give them a 'dynamically-safe property) and then
+ − 47 ;; (let ( v1 v2 ... vM vN ) <...dynamically-safe...> ) ==>
+ − 48 ;; (let ( v1 v2 ... vM ) vN <...dynamically-safe...> )
+ − 49 ;; by recursing on this, we might be able to eliminate the entire let.
+ − 50 ;; However certain variables should never have their bindings optimized
+ − 51 ;; away, because they affect everything.
+ − 52 ;; (put 'debug-on-error 'binding-is-magic t)
+ − 53 ;; (put 'debug-on-abort 'binding-is-magic t)
+ − 54 ;; (put 'debug-on-next-call 'binding-is-magic t)
+ − 55 ;; (put 'mocklisp-arguments 'binding-is-magic t)
+ − 56 ;; (put 'inhibit-quit 'binding-is-magic t)
+ − 57 ;; (put 'quit-flag 'binding-is-magic t)
+ − 58 ;; (put 't 'binding-is-magic t)
+ − 59 ;; (put 'nil 'binding-is-magic t)
+ − 60 ;; possibly also
+ − 61 ;; (put 'gc-cons-threshold 'binding-is-magic t)
+ − 62 ;; (put 'track-mouse 'binding-is-magic t)
+ − 63 ;; others?
+ − 64 ;;
+ − 65 ;; Simple defsubsts often produce forms like
+ − 66 ;; (let ((v1 (f1)) (v2 (f2)) ...)
+ − 67 ;; (FN v1 v2 ...))
440
+ − 68 ;; It would be nice if we could optimize this to
428
+ − 69 ;; (FN (f1) (f2) ...)
+ − 70 ;; but we can't unless FN is dynamically-safe (it might be dynamically
+ − 71 ;; referring to the bindings that the lambda arglist established.)
+ − 72 ;; One of the uncountable lossages introduced by dynamic scope...
+ − 73 ;;
440
+ − 74 ;; Maybe there should be a control-structure that says "turn on
428
+ − 75 ;; fast-and-loose type-assumptive optimizations here." Then when
+ − 76 ;; we see a form like (car foo) we can from then on assume that
+ − 77 ;; the variable foo is of type cons, and optimize based on that.
440
+ − 78 ;; But, this won't win much because of (you guessed it) dynamic
428
+ − 79 ;; scope. Anything down the stack could change the value.
+ − 80 ;; (Another reason it doesn't work is that it is perfectly valid
+ − 81 ;; to call car with a null argument.) A better approach might
+ − 82 ;; be to allow type-specification of the form
+ − 83 ;; (put 'foo 'arg-types '(float (list integer) dynamic))
+ − 84 ;; (put 'foo 'result-type 'bool)
+ − 85 ;; It should be possible to have these types checked to a certain
+ − 86 ;; degree.
+ − 87 ;;
+ − 88 ;; collapse common subexpressions
+ − 89 ;;
+ − 90 ;; It would be nice if redundant sequences could be factored out as well,
+ − 91 ;; when they are known to have no side-effects:
+ − 92 ;; (list (+ a b c) (+ a b c)) --> a b add c add dup list-2
+ − 93 ;; but beware of traps like
+ − 94 ;; (cons (list x y) (list x y))
+ − 95 ;;
+ − 96 ;; Tail-recursion elimination is not really possible in Emacs Lisp.
+ − 97 ;; Tail-recursion elimination is almost always impossible when all variables
+ − 98 ;; have dynamic scope, but given that the "return" byteop requires the
+ − 99 ;; binding stack to be empty (rather than emptying it itself), there can be
+ − 100 ;; no truly tail-recursive Emacs Lisp functions that take any arguments or
+ − 101 ;; make any bindings.
+ − 102 ;;
+ − 103 ;; Here is an example of an Emacs Lisp function which could safely be
+ − 104 ;; byte-compiled tail-recursively:
+ − 105 ;;
+ − 106 ;; (defun tail-map (fn list)
+ − 107 ;; (cond (list
+ − 108 ;; (funcall fn (car list))
+ − 109 ;; (tail-map fn (cdr list)))))
+ − 110 ;;
+ − 111 ;; However, if there was even a single let-binding around the COND,
+ − 112 ;; it could not be byte-compiled, because there would be an "unbind"
440
+ − 113 ;; byte-op between the final "call" and "return." Adding a
428
+ − 114 ;; Bunbind_all byteop would fix this.
+ − 115 ;;
+ − 116 ;; (defun foo (x y z) ... (foo a b c))
+ − 117 ;; ... (const foo) (varref a) (varref b) (varref c) (call 3) END: (return)
+ − 118 ;; ... (varref a) (varbind x) (varref b) (varbind y) (varref c) (varbind z) (goto 0) END: (unbind-all) (return)
+ − 119 ;; ... (varref a) (varset x) (varref b) (varset y) (varref c) (varset z) (goto 0) END: (return)
+ − 120 ;;
+ − 121 ;; this also can be considered tail recursion:
+ − 122 ;;
+ − 123 ;; ... (const foo) (varref a) (call 1) (goto X) ... X: (return)
+ − 124 ;; could generalize this by doing the optimization
+ − 125 ;; (goto X) ... X: (return) --> (return)
+ − 126 ;;
+ − 127 ;; But this doesn't solve all of the problems: although by doing tail-
+ − 128 ;; recursion elimination in this way, the call-stack does not grow, the
+ − 129 ;; binding-stack would grow with each recursive step, and would eventually
+ − 130 ;; overflow. I don't believe there is any way around this without lexical
+ − 131 ;; scope.
+ − 132 ;;
+ − 133 ;; Wouldn't it be nice if Emacs Lisp had lexical scope.
+ − 134 ;;
440
+ − 135 ;; Idea: the form (lexical-scope) in a file means that the file may be
+ − 136 ;; compiled lexically. This proclamation is file-local. Then, within
428
+ − 137 ;; that file, "let" would establish lexical bindings, and "let-dynamic"
+ − 138 ;; would do things the old way. (Or we could use CL "declare" forms.)
+ − 139 ;; We'd have to notice defvars and defconsts, since those variables should
+ − 140 ;; always be dynamic, and attempting to do a lexical binding of them
+ − 141 ;; should simply do a dynamic binding instead.
+ − 142 ;; But! We need to know about variables that were not necessarily defvarred
+ − 143 ;; in the file being compiled (doing a boundp check isn't good enough.)
+ − 144 ;; Fdefvar() would have to be modified to add something to the plist.
+ − 145 ;;
440
+ − 146 ;; A major disadvantage of this scheme is that the interpreter and compiler
+ − 147 ;; would have different semantics for files compiled with (dynamic-scope).
428
+ − 148 ;; Since this would be a file-local optimization, there would be no way to
440
+ − 149 ;; modify the interpreter to obey this (unless the loader was hacked
428
+ − 150 ;; in some grody way, but that's a really bad idea.)
+ − 151 ;;
+ − 152 ;; HA! RMS removed the following paragraph from his version of
+ − 153 ;; byte-optimize.el.
+ − 154 ;;
+ − 155 ;; Really the Right Thing is to make lexical scope the default across
440
+ − 156 ;; the board, in the interpreter and compiler, and just FIX all of
428
+ − 157 ;; the code that relies on dynamic scope of non-defvarred variables.
+ − 158
+ − 159 ;; Other things to consider:
+ − 160
+ − 161 ;; Associative math should recognize subcalls to identical function:
+ − 162 ;;(disassemble #'(lambda (x) (+ (+ (foo) 1) (+ (bar) 2))))
+ − 163 ;; This should generate the same as (1+ x) and (1- x)
+ − 164
+ − 165 ;;(disassemble #'(lambda (x) (cons (+ x 1) (- x 1))))
+ − 166 ;; An awful lot of functions always return a non-nil value. If they're
+ − 167 ;; error free also they may act as true-constants.
+ − 168
+ − 169 ;;(disassemble #'(lambda (x) (and (point) (foo))))
440
+ − 170 ;; When
428
+ − 171 ;; - all but one arguments to a function are constant
+ − 172 ;; - the non-constant argument is an if-expression (cond-expression?)
+ − 173 ;; then the outer function can be distributed. If the guarding
+ − 174 ;; condition is side-effect-free [assignment-free] then the other
+ − 175 ;; arguments may be any expressions. Since, however, the code size
+ − 176 ;; can increase this way they should be "simple". Compare:
+ − 177
+ − 178 ;;(disassemble #'(lambda (x) (eq (if (point) 'a 'b) 'c)))
+ − 179 ;;(disassemble #'(lambda (x) (if (point) (eq 'a 'c) (eq 'b 'c))))
+ − 180
444
+ − 181 ;; (car (cons A B)) -> (prog1 A B)
428
+ − 182 ;;(disassemble #'(lambda (x) (car (cons (foo) 42))))
+ − 183
+ − 184 ;; (cdr (cons A B)) -> (progn A B)
+ − 185 ;;(disassemble #'(lambda (x) (cdr (cons 42 (foo)))))
+ − 186
444
+ − 187 ;; (car (list A B ...)) -> (prog1 A ... B)
428
+ − 188 ;;(disassemble #'(lambda (x) (car (list (foo) 42 (bar)))))
+ − 189
+ − 190 ;; (cdr (list A B ...)) -> (progn A (list B ...))
+ − 191 ;;(disassemble #'(lambda (x) (cdr (list 42 (foo) (bar)))))
+ − 192
+ − 193
+ − 194 ;;; Code:
+ − 195
+ − 196 (require 'byte-compile "bytecomp")
+ − 197
+ − 198 (defun byte-compile-log-lap-1 (format &rest args)
+ − 199 (if (aref byte-code-vector 0)
+ − 200 (error "The old version of the disassembler is loaded. Reload new-bytecomp as well."))
+ − 201 (byte-compile-log-1
+ − 202 (apply 'format format
+ − 203 (let (c a)
+ − 204 (mapcar
+ − 205 #'(lambda (arg)
+ − 206 (if (not (consp arg))
+ − 207 (if (and (symbolp arg)
+ − 208 (string-match "^byte-" (symbol-name arg)))
+ − 209 (intern (substring (symbol-name arg) 5))
+ − 210 arg)
+ − 211 (if (integerp (setq c (car arg)))
+ − 212 (error "non-symbolic byte-op %s" c))
+ − 213 (if (eq c 'TAG)
+ − 214 (setq c arg)
+ − 215 (setq a (cond ((memq c byte-goto-ops)
+ − 216 (car (cdr (cdr arg))))
+ − 217 ((memq c byte-constref-ops)
+ − 218 (car (cdr arg)))
+ − 219 (t (cdr arg))))
+ − 220 (setq c (symbol-name c))
+ − 221 (if (string-match "^byte-." c)
+ − 222 (setq c (intern (substring c 5)))))
+ − 223 (if (eq c 'constant) (setq c 'const))
+ − 224 (if (and (eq (cdr arg) 0)
+ − 225 (not (memq c '(unbind call const))))
+ − 226 c
+ − 227 (format "(%s %s)" c a))))
+ − 228 args)))))
+ − 229
+ − 230 (defmacro byte-compile-log-lap (format-string &rest args)
+ − 231 (list 'and
+ − 232 '(memq byte-optimize-log '(t byte))
+ − 233 (cons 'byte-compile-log-lap-1
+ − 234 (cons format-string args))))
+ − 235
+ − 236
+ − 237 ;;; byte-compile optimizers to support inlining
+ − 238
+ − 239 (put 'inline 'byte-optimizer 'byte-optimize-inline-handler)
+ − 240
+ − 241 (defun byte-optimize-inline-handler (form)
+ − 242 "byte-optimize-handler for the `inline' special-form."
+ − 243 (cons
+ − 244 'progn
+ − 245 (mapcar
+ − 246 #'(lambda (sexp)
+ − 247 (let ((fn (car-safe sexp)))
+ − 248 (if (and (symbolp fn)
+ − 249 (or (cdr (assq fn byte-compile-function-environment))
+ − 250 (and (fboundp fn)
+ − 251 (not (or (cdr (assq fn byte-compile-macro-environment))
+ − 252 (and (consp (setq fn (symbol-function fn)))
+ − 253 (eq (car fn) 'macro))
+ − 254 (subrp fn))))))
+ − 255 (byte-compile-inline-expand sexp)
+ − 256 sexp)))
+ − 257 (cdr form))))
+ − 258
+ − 259
+ − 260 ;; Splice the given lap code into the current instruction stream.
+ − 261 ;; If it has any labels in it, you're responsible for making sure there
+ − 262 ;; are no collisions, and that byte-compile-tag-number is reasonable
+ − 263 ;; after this is spliced in. The provided list is destroyed.
+ − 264 (defun byte-inline-lapcode (lap)
+ − 265 (setq byte-compile-output (nconc (nreverse lap) byte-compile-output)))
+ − 266
+ − 267
+ − 268 (defun byte-compile-inline-expand (form)
+ − 269 (let* ((name (car form))
+ − 270 (fn (or (cdr (assq name byte-compile-function-environment))
+ − 271 (and (fboundp name) (symbol-function name)))))
+ − 272 (if (null fn)
+ − 273 (progn
+ − 274 (byte-compile-warn "attempt to inline %s before it was defined" name)
+ − 275 form)
+ − 276 ;; else
+ − 277 (if (and (consp fn) (eq (car fn) 'autoload))
+ − 278 (progn
+ − 279 (load (nth 1 fn))
+ − 280 (setq fn (or (cdr (assq name byte-compile-function-environment))
+ − 281 (and (fboundp name) (symbol-function name))))))
+ − 282 (if (and (consp fn) (eq (car fn) 'autoload))
+ − 283 (error "file \"%s\" didn't define \"%s\"" (nth 1 fn) name))
+ − 284 (if (symbolp fn)
+ − 285 (byte-compile-inline-expand (cons fn (cdr form)))
+ − 286 (if (compiled-function-p fn)
+ − 287 (progn
+ − 288 (fetch-bytecode fn)
+ − 289 (cons (list 'lambda (compiled-function-arglist fn)
+ − 290 (list 'byte-code
+ − 291 (compiled-function-instructions fn)
+ − 292 (compiled-function-constants fn)
+ − 293 (compiled-function-stack-depth fn)))
+ − 294 (cdr form)))
+ − 295 (if (not (eq (car fn) 'lambda)) (error "%s is not a lambda" name))
+ − 296 (cons fn (cdr form)))))))
+ − 297
+ − 298 ;;; ((lambda ...) ...)
440
+ − 299 ;;;
428
+ − 300 (defun byte-compile-unfold-lambda (form &optional name)
+ − 301 (or name (setq name "anonymous lambda"))
+ − 302 (let ((lambda (car form))
+ − 303 (values (cdr form)))
+ − 304 (if (compiled-function-p lambda)
+ − 305 (setq lambda (list 'lambda (compiled-function-arglist lambda)
+ − 306 (list 'byte-code
+ − 307 (compiled-function-instructions lambda)
+ − 308 (compiled-function-constants lambda)
+ − 309 (compiled-function-stack-depth lambda)))))
+ − 310 (let ((arglist (nth 1 lambda))
+ − 311 (body (cdr (cdr lambda)))
+ − 312 optionalp restp
+ − 313 bindings)
+ − 314 (if (and (stringp (car body)) (cdr body))
+ − 315 (setq body (cdr body)))
+ − 316 (if (and (consp (car body)) (eq 'interactive (car (car body))))
+ − 317 (setq body (cdr body)))
+ − 318 (while arglist
+ − 319 (cond ((eq (car arglist) '&optional)
+ − 320 ;; ok, I'll let this slide because funcall_lambda() does...
+ − 321 ;; (if optionalp (error "multiple &optional keywords in %s" name))
+ − 322 (if restp (error "&optional found after &rest in %s" name))
+ − 323 (if (null (cdr arglist))
+ − 324 (error "nothing after &optional in %s" name))
+ − 325 (setq optionalp t))
+ − 326 ((eq (car arglist) '&rest)
+ − 327 ;; ...but it is by no stretch of the imagination a reasonable
+ − 328 ;; thing that funcall_lambda() allows (&rest x y) and
+ − 329 ;; (&rest x &optional y) in arglists.
+ − 330 (if (null (cdr arglist))
+ − 331 (error "nothing after &rest in %s" name))
+ − 332 (if (cdr (cdr arglist))
+ − 333 (error "multiple vars after &rest in %s" name))
+ − 334 (setq restp t))
+ − 335 (restp
+ − 336 (setq bindings (cons (list (car arglist)
+ − 337 (and values (cons 'list values)))
+ − 338 bindings)
+ − 339 values nil))
+ − 340 ((and (not optionalp) (null values))
+ − 341 (byte-compile-warn "attempt to open-code %s with too few arguments" name)
+ − 342 (setq arglist nil values 'too-few))
+ − 343 (t
+ − 344 (setq bindings (cons (list (car arglist) (car values))
+ − 345 bindings)
+ − 346 values (cdr values))))
+ − 347 (setq arglist (cdr arglist)))
+ − 348 (if values
+ − 349 (progn
+ − 350 (or (eq values 'too-few)
+ − 351 (byte-compile-warn
+ − 352 "attempt to open-code %s with too many arguments" name))
+ − 353 form)
440
+ − 354 (let ((newform
428
+ − 355 (if bindings
+ − 356 (cons 'let (cons (nreverse bindings) body))
+ − 357 (cons 'progn body))))
+ − 358 (byte-compile-log " %s\t==>\t%s" form newform)
+ − 359 newform)))))
+ − 360
+ − 361
+ − 362 ;;; implementing source-level optimizers
+ − 363
+ − 364 (defun byte-optimize-form-code-walker (form for-effect)
+ − 365 ;;
+ − 366 ;; For normal function calls, We can just mapcar the optimizer the cdr. But
+ − 367 ;; we need to have special knowledge of the syntax of the special forms
+ − 368 ;; like let and defun (that's why they're special forms :-). (Actually,
+ − 369 ;; the important aspect is that they are subrs that don't evaluate all of
+ − 370 ;; their args.)
+ − 371 ;;
+ − 372 (let ((fn (car-safe form))
+ − 373 tmp)
+ − 374 (cond ((not (consp form))
+ − 375 (if (not (and for-effect
+ − 376 (or byte-compile-delete-errors
+ − 377 (not (symbolp form))
+ − 378 (eq form t))))
+ − 379 form))
+ − 380 ((eq fn 'quote)
+ − 381 (if (cdr (cdr form))
+ − 382 (byte-compile-warn "malformed quote form: %s"
+ − 383 (prin1-to-string form)))
+ − 384 ;; map (quote nil) to nil to simplify optimizer logic.
+ − 385 ;; map quoted constants to nil if for-effect (just because).
+ − 386 (and (nth 1 form)
+ − 387 (not for-effect)
+ − 388 form))
+ − 389 ((or (compiled-function-p fn)
+ − 390 (eq 'lambda (car-safe fn)))
+ − 391 (byte-compile-unfold-lambda form))
+ − 392 ((memq fn '(let let*))
+ − 393 ;; recursively enter the optimizer for the bindings and body
+ − 394 ;; of a let or let*. This for depth-firstness: forms that
+ − 395 ;; are more deeply nested are optimized first.
+ − 396 (cons fn
+ − 397 (cons
+ − 398 (mapcar
+ − 399 #'(lambda (binding)
+ − 400 (if (symbolp binding)
+ − 401 binding
+ − 402 (if (cdr (cdr binding))
+ − 403 (byte-compile-warn "malformed let binding: %s"
+ − 404 (prin1-to-string binding)))
+ − 405 (list (car binding)
+ − 406 (byte-optimize-form (nth 1 binding) nil))))
+ − 407 (nth 1 form))
+ − 408 (byte-optimize-body (cdr (cdr form)) for-effect))))
+ − 409 ((eq fn 'cond)
+ − 410 (cons fn
+ − 411 (mapcar
+ − 412 #'(lambda (clause)
+ − 413 (if (consp clause)
+ − 414 (cons
+ − 415 (byte-optimize-form (car clause) nil)
+ − 416 (byte-optimize-body (cdr clause) for-effect))
+ − 417 (byte-compile-warn "malformed cond form: %s"
+ − 418 (prin1-to-string clause))
+ − 419 clause))
+ − 420 (cdr form))))
+ − 421 ((eq fn 'progn)
+ − 422 ;; as an extra added bonus, this simplifies (progn <x>) --> <x>
+ − 423 (if (cdr (cdr form))
+ − 424 (progn
+ − 425 (setq tmp (byte-optimize-body (cdr form) for-effect))
+ − 426 (if (cdr tmp) (cons 'progn tmp) (car tmp)))
+ − 427 (byte-optimize-form (nth 1 form) for-effect)))
+ − 428 ((eq fn 'prog1)
+ − 429 (if (cdr (cdr form))
+ − 430 (cons 'prog1
+ − 431 (cons (byte-optimize-form (nth 1 form) for-effect)
+ − 432 (byte-optimize-body (cdr (cdr form)) t)))
+ − 433 (byte-optimize-form (nth 1 form) for-effect)))
+ − 434 ((eq fn 'prog2)
+ − 435 (cons 'prog2
+ − 436 (cons (byte-optimize-form (nth 1 form) t)
+ − 437 (cons (byte-optimize-form (nth 2 form) for-effect)
+ − 438 (byte-optimize-body (cdr (cdr (cdr form))) t)))))
440
+ − 439
428
+ − 440 ((memq fn '(save-excursion save-restriction save-current-buffer))
+ − 441 ;; those subrs which have an implicit progn; it's not quite good
+ − 442 ;; enough to treat these like normal function calls.
+ − 443 ;; This can turn (save-excursion ...) into (save-excursion) which
+ − 444 ;; will be optimized away in the lap-optimize pass.
+ − 445 (cons fn (byte-optimize-body (cdr form) for-effect)))
440
+ − 446
428
+ − 447 ((eq fn 'with-output-to-temp-buffer)
+ − 448 ;; this is just like the above, except for the first argument.
+ − 449 (cons fn
+ − 450 (cons
+ − 451 (byte-optimize-form (nth 1 form) nil)
+ − 452 (byte-optimize-body (cdr (cdr form)) for-effect))))
440
+ − 453
428
+ − 454 ((eq fn 'if)
+ − 455 (cons fn
+ − 456 (cons (byte-optimize-form (nth 1 form) nil)
+ − 457 (cons
+ − 458 (byte-optimize-form (nth 2 form) for-effect)
+ − 459 (byte-optimize-body (nthcdr 3 form) for-effect)))))
440
+ − 460
428
+ − 461 ((memq fn '(and or)) ; remember, and/or are control structures.
+ − 462 ;; take forms off the back until we can't any more.
+ − 463 ;; In the future it could conceivably be a problem that the
+ − 464 ;; subexpressions of these forms are optimized in the reverse
+ − 465 ;; order, but it's ok for now.
+ − 466 (if for-effect
+ − 467 (let ((backwards (reverse (cdr form))))
+ − 468 (while (and backwards
+ − 469 (null (setcar backwards
+ − 470 (byte-optimize-form (car backwards)
+ − 471 for-effect))))
+ − 472 (setq backwards (cdr backwards)))
+ − 473 (if (and (cdr form) (null backwards))
+ − 474 (byte-compile-log
+ − 475 " all subforms of %s called for effect; deleted" form))
452
+ − 476 (when backwards
+ − 477 ;; Now optimize the rest of the forms. We need the return
+ − 478 ;; values. We already did the car.
+ − 479 (setcdr backwards
+ − 480 (mapcar 'byte-optimize-form (cdr backwards))))
+ − 481 (cons fn (nreverse backwards)))
428
+ − 482 (cons fn (mapcar 'byte-optimize-form (cdr form)))))
+ − 483
+ − 484 ((eq fn 'interactive)
+ − 485 (byte-compile-warn "misplaced interactive spec: %s"
+ − 486 (prin1-to-string form))
+ − 487 nil)
440
+ − 488
428
+ − 489 ((memq fn '(defun defmacro function
+ − 490 condition-case save-window-excursion))
+ − 491 ;; These forms are compiled as constants or by breaking out
+ − 492 ;; all the subexpressions and compiling them separately.
+ − 493 form)
+ − 494
+ − 495 ((eq fn 'unwind-protect)
+ − 496 ;; the "protected" part of an unwind-protect is compiled (and thus
+ − 497 ;; optimized) as a top-level form, so don't do it here. But the
+ − 498 ;; non-protected part has the same for-effect status as the
+ − 499 ;; unwind-protect itself. (The protected part is always for effect,
+ − 500 ;; but that isn't handled properly yet.)
+ − 501 (cons fn
+ − 502 (cons (byte-optimize-form (nth 1 form) for-effect)
+ − 503 (cdr (cdr form)))))
440
+ − 504
428
+ − 505 ((eq fn 'catch)
+ − 506 ;; the body of a catch is compiled (and thus optimized) as a
+ − 507 ;; top-level form, so don't do it here. The tag is never
+ − 508 ;; for-effect. The body should have the same for-effect status
+ − 509 ;; as the catch form itself, but that isn't handled properly yet.
+ − 510 (cons fn
+ − 511 (cons (byte-optimize-form (nth 1 form) nil)
+ − 512 (cdr (cdr form)))))
+ − 513
+ − 514 ;; If optimization is on, this is the only place that macros are
+ − 515 ;; expanded. If optimization is off, then macroexpansion happens
+ − 516 ;; in byte-compile-form. Otherwise, the macros are already expanded
+ − 517 ;; by the time that is reached.
+ − 518 ((not (eq form
+ − 519 (setq form (macroexpand form
+ − 520 byte-compile-macro-environment))))
+ − 521 (byte-optimize-form form for-effect))
440
+ − 522
428
+ − 523 ((not (symbolp fn))
+ − 524 (or (eq 'mocklisp (car-safe fn)) ; ha!
+ − 525 (byte-compile-warn "%s is a malformed function"
+ − 526 (prin1-to-string fn)))
+ − 527 form)
+ − 528
+ − 529 ((and for-effect (setq tmp (get fn 'side-effect-free))
+ − 530 (or byte-compile-delete-errors
+ − 531 (eq tmp 'error-free)
+ − 532 (progn
+ − 533 (byte-compile-warn "%s called for effect"
+ − 534 (prin1-to-string form))
+ − 535 nil)))
+ − 536 (byte-compile-log " %s called for effect; deleted" fn)
+ − 537 ;; appending a nil here might not be necessary, but it can't hurt.
+ − 538 (byte-optimize-form
+ − 539 (cons 'progn (append (cdr form) '(nil))) t))
440
+ − 540
428
+ − 541 (t
+ − 542 ;; Otherwise, no args can be considered to be for-effect,
+ − 543 ;; even if the called function is for-effect, because we
+ − 544 ;; don't know anything about that function.
+ − 545 (cons fn (mapcar 'byte-optimize-form (cdr form)))))))
+ − 546
+ − 547
+ − 548 (defun byte-optimize-form (form &optional for-effect)
+ − 549 "The source-level pass of the optimizer."
+ − 550 ;;
+ − 551 ;; First, optimize all sub-forms of this one.
+ − 552 (setq form (byte-optimize-form-code-walker form for-effect))
+ − 553 ;;
+ − 554 ;; After optimizing all subforms, optimize this form until it doesn't
+ − 555 ;; optimize any further. This means that some forms will be passed through
+ − 556 ;; the optimizer many times, but that's necessary to make the for-effect
+ − 557 ;; processing do as much as possible.
+ − 558 ;;
+ − 559 (let (opt new)
+ − 560 (if (and (consp form)
+ − 561 (symbolp (car form))
+ − 562 (or (and for-effect
+ − 563 ;; we don't have any of these yet, but we might.
+ − 564 (setq opt (get (car form) 'byte-for-effect-optimizer)))
+ − 565 (setq opt (get (car form) 'byte-optimizer)))
+ − 566 (not (eq form (setq new (funcall opt form)))))
+ − 567 (progn
+ − 568 ;; (if (equal form new) (error "bogus optimizer -- %s" opt))
+ − 569 (byte-compile-log " %s\t==>\t%s" form new)
446
+ − 570 (byte-optimize-form new for-effect))
428
+ − 571 form)))
+ − 572
+ − 573
+ − 574 (defun byte-optimize-body (forms all-for-effect)
+ − 575 ;; Optimize the cdr of a progn or implicit progn; `forms' is a list of
+ − 576 ;; forms, all but the last of which are optimized with the assumption that
+ − 577 ;; they are being called for effect. The last is for-effect as well if
+ − 578 ;; all-for-effect is true. Returns a new list of forms.
+ − 579 (let ((rest forms)
+ − 580 (result nil)
+ − 581 fe new)
+ − 582 (while rest
+ − 583 (setq fe (or all-for-effect (cdr rest)))
+ − 584 (setq new (and (car rest) (byte-optimize-form (car rest) fe)))
+ − 585 (if (or new (not fe))
+ − 586 (setq result (cons new result)))
+ − 587 (setq rest (cdr rest)))
+ − 588 (nreverse result)))
+ − 589
+ − 590
+ − 591 ;;; some source-level optimizers
+ − 592 ;;;
+ − 593 ;;; when writing optimizers, be VERY careful that the optimizer returns
+ − 594 ;;; something not EQ to its argument if and ONLY if it has made a change.
+ − 595 ;;; This implies that you cannot simply destructively modify the list;
+ − 596 ;;; you must return something not EQ to it if you make an optimization.
+ − 597 ;;;
+ − 598 ;;; It is now safe to optimize code such that it introduces new bindings.
+ − 599
+ − 600 ;; I'd like this to be a defsubst, but let's not be self-referential...
+ − 601 (defmacro byte-compile-trueconstp (form)
+ − 602 ;; Returns non-nil if FORM is a non-nil constant.
+ − 603 `(cond ((consp ,form) (eq (car ,form) 'quote))
+ − 604 ((not (symbolp ,form)))
+ − 605 ((eq ,form t))
+ − 606 ((keywordp ,form))))
+ − 607
+ − 608 ;; If the function is being called with constant numeric args,
440
+ − 609 ;; evaluate as much as possible at compile-time. This optimizer
428
+ − 610 ;; assumes that the function is associative, like + or *.
+ − 611 (defun byte-optimize-associative-math (form)
+ − 612 (let ((args nil)
+ − 613 (constants nil)
+ − 614 (rest (cdr form)))
+ − 615 (while rest
+ − 616 (if (numberp (car rest))
+ − 617 (setq constants (cons (car rest) constants))
+ − 618 (setq args (cons (car rest) args)))
+ − 619 (setq rest (cdr rest)))
+ − 620 (if (cdr constants)
+ − 621 (if args
+ − 622 (list (car form)
+ − 623 (apply (car form) constants)
+ − 624 (if (cdr args)
+ − 625 (cons (car form) (nreverse args))
+ − 626 (car args)))
+ − 627 (apply (car form) constants))
+ − 628 form)))
+ − 629
+ − 630 ;; If the function is being called with constant numeric args,
+ − 631 ;; evaluate as much as possible at compile-time. This optimizer
+ − 632 ;; assumes that the function satisfies
+ − 633 ;; (op x1 x2 ... xn) == (op ...(op (op x1 x2) x3) ...xn)
+ − 634 ;; like - and /.
+ − 635 (defun byte-optimize-nonassociative-math (form)
+ − 636 (if (or (not (numberp (car (cdr form))))
+ − 637 (not (numberp (car (cdr (cdr form))))))
+ − 638 form
+ − 639 (let ((constant (car (cdr form)))
+ − 640 (rest (cdr (cdr form))))
+ − 641 (while (numberp (car rest))
+ − 642 (setq constant (funcall (car form) constant (car rest))
+ − 643 rest (cdr rest)))
+ − 644 (if rest
+ − 645 (cons (car form) (cons constant rest))
+ − 646 constant))))
+ − 647
+ − 648 ;;(defun byte-optimize-associative-two-args-math (form)
+ − 649 ;; (setq form (byte-optimize-associative-math form))
+ − 650 ;; (if (consp form)
+ − 651 ;; (byte-optimize-two-args-left form)
+ − 652 ;; form))
+ − 653
+ − 654 ;;(defun byte-optimize-nonassociative-two-args-math (form)
+ − 655 ;; (setq form (byte-optimize-nonassociative-math form))
+ − 656 ;; (if (consp form)
+ − 657 ;; (byte-optimize-two-args-right form)
+ − 658 ;; form))
+ − 659
+ − 660 ;; jwz: (byte-optimize-approx-equal 0.0 0.0) was returning nil
+ − 661 ;; in xemacs 19.15 because it used < instead of <=.
+ − 662 (defun byte-optimize-approx-equal (x y)
+ − 663 (<= (* (abs (- x y)) 100) (abs (+ x y))))
+ − 664
+ − 665 ;; Collect all the constants from FORM, after the STARTth arg,
+ − 666 ;; and apply FUN to them to make one argument at the end.
+ − 667 ;; For functions that can handle floats, that optimization
+ − 668 ;; can be incorrect because reordering can cause an overflow
+ − 669 ;; that would otherwise be avoided by encountering an arg that is a float.
+ − 670 ;; We avoid this problem by (1) not moving float constants and
+ − 671 ;; (2) not moving anything if it would cause an overflow.
+ − 672 (defun byte-optimize-delay-constants-math (form start fun)
+ − 673 ;; Merge all FORM's constants from number START, call FUN on them
+ − 674 ;; and put the result at the end.
+ − 675 (let ((rest (nthcdr (1- start) form))
+ − 676 (orig form)
+ − 677 ;; t means we must check for overflow.
+ − 678 (overflow (memq fun '(+ *))))
+ − 679 (while (cdr (setq rest (cdr rest)))
+ − 680 (if (integerp (car rest))
+ − 681 (let (constants)
+ − 682 (setq form (copy-sequence form)
+ − 683 rest (nthcdr (1- start) form))
+ − 684 (while (setq rest (cdr rest))
+ − 685 (cond ((integerp (car rest))
+ − 686 (setq constants (cons (car rest) constants))
+ − 687 (setcar rest nil))))
+ − 688 ;; If necessary, check now for overflow
+ − 689 ;; that might be caused by reordering.
+ − 690 (if (and overflow
+ − 691 ;; We have overflow if the result of doing the arithmetic
+ − 692 ;; on floats is not even close to the result
+ − 693 ;; of doing it on integers.
+ − 694 (not (byte-optimize-approx-equal
+ − 695 (apply fun (mapcar 'float constants))
+ − 696 (float (apply fun constants)))))
+ − 697 (setq form orig)
+ − 698 (setq form (nconc (delq nil form)
+ − 699 (list (apply fun (nreverse constants)))))))))
+ − 700 form))
+ − 701
446
+ − 702 ;;; It is not safe to optimize calls to arithmetic ops with one arg
+ − 703 ;;; away entirely (actually, it would be safe if we know the sole arg
+ − 704 ;;; is not a marker or if it appears in other arithmetic).
428
+ − 705
446
+ − 706 ;;; But this degree of paranoia is normally unjustified, so optimize unless
547
+ − 707 ;;; the user has done (declaim (optimize (safety 3))). See bytecomp.el.
442
+ − 708
446
+ − 709 (defun byte-optimize-plus (form)
+ − 710 (byte-optimize-predicate (byte-optimize-delay-constants-math form 1 '+)))
428
+ − 711
+ − 712 (defun byte-optimize-multiply (form)
+ − 713 (setq form (byte-optimize-delay-constants-math form 1 '*))
442
+ − 714 ;; If there is a constant integer in FORM, it is now the last element.
446
+ − 715
+ − 716 (case (car (last form))
+ − 717 ;; (* x y 0) --> (progn x y 0)
+ − 718 (0 (cons 'progn (cdr form)))
+ − 719 (t (byte-optimize-predicate form))))
+ − 720
+ − 721 (defun byte-optimize-minus (form)
+ − 722 ;; Put constants at the end, except the first arg.
+ − 723 (setq form (byte-optimize-delay-constants-math form 2 '+))
+ − 724 ;; Now only the first and last args can be integers.
+ − 725 (let ((last (car (last (nthcdr 3 form)))))
+ − 726 (cond
+ − 727 ;; If form is (- CONST foo... CONST), merge first and last.
+ − 728 ((and (numberp (nth 1 form)) (numberp last))
+ − 729 (decf (nth 1 form) last)
+ − 730 (butlast form))
+ − 731
464
+ − 732 ;; (- 0 ...) -->
+ − 733 ((eq 0 (nth 1 form))
+ − 734 (case (length form)
+ − 735 ;; (- 0) --> 0
+ − 736 (2 0)
+ − 737 ;; (- 0 x) --> (- x)
+ − 738 (3 `(- ,(nth 2 form)))
+ − 739 ;; (- 0 x y ...) --> (- (- x) y ...)
+ − 740 (t `(- (- ,(nth 2 form)) ,@(nthcdr 3 form)))))
446
+ − 741
+ − 742 (t (byte-optimize-predicate form)))))
428
+ − 743
+ − 744 (defun byte-optimize-divide (form)
446
+ − 745 ;; Put constants at the end, except the first arg.
428
+ − 746 (setq form (byte-optimize-delay-constants-math form 2 '*))
446
+ − 747 ;; Now only the first and last args can be integers.
+ − 748 (let ((last (car (last (nthcdr 3 form)))))
440
+ − 749 (cond
446
+ − 750 ;; If form is (/ CONST foo... CONST), merge first and last.
+ − 751 ((and (numberp (nth 1 form)) (numberp last))
+ − 752 (condition-case nil
+ − 753 (cons (nth 0 form)
+ − 754 (cons (/ (nth 1 form) last)
+ − 755 (butlast (cdr (cdr form)))))
+ − 756 (error form)))
+ − 757
+ − 758 ;; (/ 0 x y) --> (progn x y 0)
442
+ − 759 ((eq (nth 1 form) 0)
+ − 760 (append '(progn) (cdr (cdr form)) '(0)))
446
+ − 761
+ − 762 ;; We don't have to check for divide-by-zero because `/' does.
+ − 763 (t (byte-optimize-predicate form)))))
428
+ − 764
+ − 765 (defun byte-optimize-logmumble (form)
+ − 766 (setq form (byte-optimize-delay-constants-math form 1 (car form)))
+ − 767 (byte-optimize-predicate
+ − 768 (cond ((memq 0 form)
+ − 769 (setq form (if (eq (car form) 'logand)
+ − 770 (cons 'progn (cdr form))
+ − 771 (delq 0 (copy-sequence form)))))
+ − 772 ((and (eq (car-safe form) 'logior)
+ − 773 (memq -1 form))
+ − 774 (cons 'progn (cdr form)))
+ − 775 (form))))
+ − 776
+ − 777
+ − 778 (defun byte-optimize-binary-predicate (form)
+ − 779 (if (byte-compile-constp (nth 1 form))
+ − 780 (if (byte-compile-constp (nth 2 form))
+ − 781 (condition-case ()
+ − 782 (list 'quote (eval form))
+ − 783 (error form))
+ − 784 ;; This can enable some lapcode optimizations.
+ − 785 (list (car form) (nth 2 form) (nth 1 form)))
+ − 786 form))
+ − 787
+ − 788 (defun byte-optimize-predicate (form)
+ − 789 (let ((ok t)
+ − 790 (rest (cdr form)))
+ − 791 (while (and rest ok)
+ − 792 (setq ok (byte-compile-constp (car rest))
+ − 793 rest (cdr rest)))
+ − 794 (if ok
446
+ − 795 (condition-case err
428
+ − 796 (list 'quote (eval form))
446
+ − 797 (error
+ − 798 (byte-compile-warn "evaluating %s: %s" form err)
+ − 799 form))
428
+ − 800 form)))
+ − 801
+ − 802 (defun byte-optimize-identity (form)
+ − 803 (if (and (cdr form) (null (cdr (cdr form))))
+ − 804 (nth 1 form)
+ − 805 (byte-compile-warn "identity called with %d arg%s, but requires 1"
+ − 806 (length (cdr form))
+ − 807 (if (= 1 (length (cdr form))) "" "s"))
+ − 808 form))
+ − 809
444
+ − 810 (defun byte-optimize-car (form)
+ − 811 (let ((arg (cadr form)))
+ − 812 (cond
+ − 813 ((and (byte-compile-trueconstp arg)
+ − 814 (not (and (consp arg)
+ − 815 (eq (car arg) 'quote)
+ − 816 (listp (cadr arg)))))
+ − 817 (byte-compile-warn
+ − 818 "taking car of a constant: %s" arg)
+ − 819 form)
+ − 820 ((and (eq (car-safe arg) 'cons)
+ − 821 (eq (length arg) 3))
+ − 822 `(prog1 ,(nth 1 arg) ,(nth 2 arg)))
+ − 823 ((eq (car-safe arg) 'list)
+ − 824 `(prog1 ,@(cdr arg)))
+ − 825 (t
+ − 826 (byte-optimize-predicate form)))))
+ − 827
+ − 828 (defun byte-optimize-cdr (form)
+ − 829 (let ((arg (cadr form)))
+ − 830 (cond
+ − 831 ((and (byte-compile-trueconstp arg)
+ − 832 (not (and (consp arg)
+ − 833 (eq (car arg) 'quote)
+ − 834 (listp (cadr arg)))))
+ − 835 (byte-compile-warn
+ − 836 "taking cdr of a constant: %s" arg)
+ − 837 form)
+ − 838 ((and (eq (car-safe arg) 'cons)
+ − 839 (eq (length arg) 3))
+ − 840 `(progn ,(nth 1 arg) ,(nth 2 arg)))
+ − 841 ((eq (car-safe arg) 'list)
+ − 842 (if (> (length arg) 2)
+ − 843 `(progn ,(cadr arg) (list ,@(cddr arg)))
+ − 844 (cadr arg)))
+ − 845 (t
+ − 846 (byte-optimize-predicate form)))))
+ − 847
428
+ − 848 (put 'identity 'byte-optimizer 'byte-optimize-identity)
+ − 849
+ − 850 (put '+ 'byte-optimizer 'byte-optimize-plus)
+ − 851 (put '* 'byte-optimizer 'byte-optimize-multiply)
+ − 852 (put '- 'byte-optimizer 'byte-optimize-minus)
+ − 853 (put '/ 'byte-optimizer 'byte-optimize-divide)
446
+ − 854 (put '% 'byte-optimizer 'byte-optimize-predicate)
428
+ − 855 (put 'max 'byte-optimizer 'byte-optimize-associative-math)
+ − 856 (put 'min 'byte-optimizer 'byte-optimize-associative-math)
+ − 857
+ − 858 (put 'eq 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 859 (put 'eql 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 860 (put 'equal 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 861 (put 'string= 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 862 (put 'string-equal 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 863
550
+ − 864 (put '= 'byte-optimizer 'byte-optimize-predicate)
428
+ − 865 (put '< 'byte-optimizer 'byte-optimize-predicate)
+ − 866 (put '> 'byte-optimizer 'byte-optimize-predicate)
+ − 867 (put '<= 'byte-optimizer 'byte-optimize-predicate)
+ − 868 (put '>= 'byte-optimizer 'byte-optimize-predicate)
+ − 869 (put '1+ 'byte-optimizer 'byte-optimize-predicate)
+ − 870 (put '1- 'byte-optimizer 'byte-optimize-predicate)
+ − 871 (put 'not 'byte-optimizer 'byte-optimize-predicate)
+ − 872 (put 'null 'byte-optimizer 'byte-optimize-predicate)
+ − 873 (put 'memq 'byte-optimizer 'byte-optimize-predicate)
+ − 874 (put 'consp 'byte-optimizer 'byte-optimize-predicate)
+ − 875 (put 'listp 'byte-optimizer 'byte-optimize-predicate)
+ − 876 (put 'symbolp 'byte-optimizer 'byte-optimize-predicate)
+ − 877 (put 'stringp 'byte-optimizer 'byte-optimize-predicate)
+ − 878 (put 'string< 'byte-optimizer 'byte-optimize-predicate)
+ − 879 (put 'string-lessp 'byte-optimizer 'byte-optimize-predicate)
440
+ − 880 (put 'length 'byte-optimizer 'byte-optimize-predicate)
428
+ − 881
+ − 882 (put 'logand 'byte-optimizer 'byte-optimize-logmumble)
+ − 883 (put 'logior 'byte-optimizer 'byte-optimize-logmumble)
+ − 884 (put 'logxor 'byte-optimizer 'byte-optimize-logmumble)
+ − 885 (put 'lognot 'byte-optimizer 'byte-optimize-predicate)
+ − 886
444
+ − 887 (put 'car 'byte-optimizer 'byte-optimize-car)
+ − 888 (put 'cdr 'byte-optimizer 'byte-optimize-cdr)
428
+ − 889 (put 'car-safe 'byte-optimizer 'byte-optimize-predicate)
+ − 890 (put 'cdr-safe 'byte-optimizer 'byte-optimize-predicate)
+ − 891
+ − 892
440
+ − 893 ;; I'm not convinced that this is necessary. Doesn't the optimizer loop
428
+ − 894 ;; take care of this? - Jamie
+ − 895 ;; I think this may some times be necessary to reduce eg. (quote 5) to 5,
+ − 896 ;; so arithmetic optimizers recognize the numeric constant. - Hallvard
+ − 897 (put 'quote 'byte-optimizer 'byte-optimize-quote)
+ − 898 (defun byte-optimize-quote (form)
+ − 899 (if (or (consp (nth 1 form))
+ − 900 (and (symbolp (nth 1 form))
+ − 901 ;; XEmacs addition:
+ − 902 (not (keywordp (nth 1 form)))
+ − 903 (not (memq (nth 1 form) '(nil t)))))
+ − 904 form
+ − 905 (nth 1 form)))
+ − 906
+ − 907 (defun byte-optimize-zerop (form)
+ − 908 (cond ((numberp (nth 1 form))
+ − 909 (eval form))
+ − 910 (byte-compile-delete-errors
+ − 911 (list '= (nth 1 form) 0))
+ − 912 (form)))
+ − 913
+ − 914 (put 'zerop 'byte-optimizer 'byte-optimize-zerop)
+ − 915
+ − 916 (defun byte-optimize-and (form)
+ − 917 ;; Simplify if less than 2 args.
+ − 918 ;; if there is a literal nil in the args to `and', throw it and following
+ − 919 ;; forms away, and surround the `and' with (progn ... nil).
+ − 920 (cond ((null (cdr form)))
+ − 921 ((memq nil form)
+ − 922 (list 'progn
+ − 923 (byte-optimize-and
+ − 924 (prog1 (setq form (copy-sequence form))
+ − 925 (while (nth 1 form)
+ − 926 (setq form (cdr form)))
+ − 927 (setcdr form nil)))
+ − 928 nil))
+ − 929 ((null (cdr (cdr form)))
+ − 930 (nth 1 form))
+ − 931 ((byte-optimize-predicate form))))
+ − 932
+ − 933 (defun byte-optimize-or (form)
+ − 934 ;; Throw away nil's, and simplify if less than 2 args.
+ − 935 ;; If there is a literal non-nil constant in the args to `or', throw away all
+ − 936 ;; following forms.
+ − 937 (if (memq nil form)
+ − 938 (setq form (delq nil (copy-sequence form))))
+ − 939 (let ((rest form))
+ − 940 (while (cdr (setq rest (cdr rest)))
+ − 941 (if (byte-compile-trueconstp (car rest))
+ − 942 (setq form (copy-sequence form)
+ − 943 rest (setcdr (memq (car rest) form) nil))))
+ − 944 (if (cdr (cdr form))
+ − 945 (byte-optimize-predicate form)
+ − 946 (nth 1 form))))
+ − 947
448
+ − 948 ;;; For the byte optimizer, `cond' is just overly sweet syntactic sugar.
+ − 949 ;;; So we rewrite (cond ...) in terms of `if' and `or',
+ − 950 ;;; which are easier to optimize.
428
+ − 951 (defun byte-optimize-cond (form)
448
+ − 952 (byte-optimize-cond-1 (cdr form)))
+ − 953
+ − 954 (defun byte-optimize-cond-1 (clauses)
+ − 955 (cond
+ − 956 ((null clauses) nil)
+ − 957 ((consp (car clauses))
+ − 958 (nconc
+ − 959 (case (length (car clauses))
+ − 960 (1 `(or ,(nth 0 (car clauses))))
+ − 961 (2 `(if ,(nth 0 (car clauses)) ,(nth 1 (car clauses))))
+ − 962 (t `(if ,(nth 0 (car clauses)) (progn ,@(cdr (car clauses))))))
+ − 963 (when (cdr clauses) (list (byte-optimize-cond-1 (cdr clauses))))))
+ − 964 (t (error "malformed cond clause %s" (car clauses)))))
428
+ − 965
+ − 966 (defun byte-optimize-if (form)
+ − 967 ;; (if <true-constant> <then> <else...>) ==> <then>
+ − 968 ;; (if <false-constant> <then> <else...>) ==> (progn <else...>)
+ − 969 ;; (if <test> nil <else...>) ==> (if (not <test>) (progn <else...>))
+ − 970 ;; (if <test> <then> nil) ==> (if <test> <then>)
+ − 971 (let ((clause (nth 1 form)))
+ − 972 (cond ((byte-compile-trueconstp clause)
+ − 973 (nth 2 form))
+ − 974 ((null clause)
+ − 975 (if (nthcdr 4 form)
+ − 976 (cons 'progn (nthcdr 3 form))
+ − 977 (nth 3 form)))
+ − 978 ((nth 2 form)
+ − 979 (if (equal '(nil) (nthcdr 3 form))
+ − 980 (list 'if clause (nth 2 form))
+ − 981 form))
+ − 982 ((or (nth 3 form) (nthcdr 4 form))
+ − 983 (list 'if
+ − 984 ;; Don't make a double negative;
+ − 985 ;; instead, take away the one that is there.
+ − 986 (if (and (consp clause) (memq (car clause) '(not null))
+ − 987 (= (length clause) 2)) ; (not xxxx) or (not (xxxx))
+ − 988 (nth 1 clause)
+ − 989 (list 'not clause))
+ − 990 (if (nthcdr 4 form)
+ − 991 (cons 'progn (nthcdr 3 form))
+ − 992 (nth 3 form))))
+ − 993 (t
+ − 994 (list 'progn clause nil)))))
+ − 995
+ − 996 (defun byte-optimize-while (form)
+ − 997 (if (nth 1 form)
+ − 998 form))
+ − 999
+ − 1000 (put 'and 'byte-optimizer 'byte-optimize-and)
+ − 1001 (put 'or 'byte-optimizer 'byte-optimize-or)
+ − 1002 (put 'cond 'byte-optimizer 'byte-optimize-cond)
+ − 1003 (put 'if 'byte-optimizer 'byte-optimize-if)
+ − 1004 (put 'while 'byte-optimizer 'byte-optimize-while)
+ − 1005
446
+ − 1006 ;; The supply of bytecodes is small and constrained by backward compatibility.
+ − 1007 ;; Several functions have byte-coded versions and hence are very efficient.
+ − 1008 ;; Related functions which can be expressed in terms of the byte-coded
+ − 1009 ;; ones should be transformed into bytecoded calls for efficiency.
+ − 1010 ;; This is especially the case for functions with a backward- and
+ − 1011 ;; forward- version, but with a bytecode only for the forward one.
+ − 1012
+ − 1013 ;; Some programmers have hand-optimized calls like (backward-char)
+ − 1014 ;; into the call (forward-char -1).
+ − 1015 ;; But it's so much nicer for the byte-compiler to do this automatically!
+ − 1016
+ − 1017 ;; (char-before) ==> (char-after (1- (point)))
+ − 1018 (put 'char-before 'byte-optimizer 'byte-optimize-char-before)
434
+ − 1019 (defun byte-optimize-char-before (form)
446
+ − 1020 `(char-after
+ − 1021 ,(cond
+ − 1022 ((null (nth 1 form))
+ − 1023 '(1- (point)))
+ − 1024 ((equal '(point) (nth 1 form))
+ − 1025 '(1- (point)))
+ − 1026 (t `(1- (or ,(nth 1 form) (point)))))
+ − 1027 ,@(cdr (cdr form))))
+ − 1028
+ − 1029 ;; (backward-char n) ==> (forward-char (- n))
+ − 1030 (put 'backward-char 'byte-optimizer 'byte-optimize-backward-char)
+ − 1031 (defun byte-optimize-backward-char (form)
+ − 1032 `(forward-char
+ − 1033 ,(typecase (nth 1 form)
+ − 1034 (null -1)
+ − 1035 (integer (- (nth 1 form)))
+ − 1036 (t `(- (or ,(nth 1 form) 1))))
+ − 1037 ,@(cdr (cdr form))))
440
+ − 1038
446
+ − 1039 ;; (backward-word n) ==> (forward-word (- n))
+ − 1040 (put 'backward-word 'byte-optimizer 'byte-optimize-backward-word)
+ − 1041 (defun byte-optimize-backward-word (form)
+ − 1042 `(forward-word
+ − 1043 ,(typecase (nth 1 form)
+ − 1044 (null -1)
+ − 1045 (integer (- (nth 1 form)))
+ − 1046 (t `(- (or ,(nth 1 form) 1))))
+ − 1047 ,@(cdr (cdr form))))
+ − 1048
+ − 1049 ;; The following would be a valid optimization of the above kind, but
+ − 1050 ;; the gain in performance is very small, since the saved funcall is
+ − 1051 ;; counterbalanced by the necessity of adding a bytecode for (point).
+ − 1052 ;;
+ − 1053 ;; Also, users are more likely to have modified the behavior of
+ − 1054 ;; delete-char via advice or some similar mechanism. This is much
+ − 1055 ;; less of a problem for the previous functions because it wouldn't
+ − 1056 ;; make sense to modify the behaviour of `backward-char' without also
+ − 1057 ;; modifying `forward-char', for example.
+ − 1058
+ − 1059 ;; (delete-char n) ==> (delete-region (point) (+ (point) n))
+ − 1060 ;; (put 'delete-char 'byte-optimizer 'byte-optimize-delete-char)
+ − 1061 ;; (defun byte-optimize-delete-char (form)
+ − 1062 ;; (case (length (cdr form))
+ − 1063 ;; (0 `(delete-region (point) (1+ (point))))
+ − 1064 ;; (1 `(delete-region (point) (+ (point) ,(nth 1 form))))
+ − 1065 ;; (t form)))
434
+ − 1066
428
+ − 1067 ;; byte-compile-negation-optimizer lives in bytecomp.el
+ − 1068 ;(put '/= 'byte-optimizer 'byte-compile-negation-optimizer)
+ − 1069 (put 'atom 'byte-optimizer 'byte-compile-negation-optimizer)
+ − 1070 (put 'nlistp 'byte-optimizer 'byte-compile-negation-optimizer)
+ − 1071
+ − 1072 (defun byte-optimize-funcall (form)
+ − 1073 ;; (funcall '(lambda ...) ...) ==> ((lambda ...) ...)
+ − 1074 ;; (funcall 'foo ...) ==> (foo ...)
+ − 1075 (let ((fn (nth 1 form)))
+ − 1076 (if (memq (car-safe fn) '(quote function))
+ − 1077 (cons (nth 1 fn) (cdr (cdr form)))
+ − 1078 form)))
+ − 1079
+ − 1080 (defun byte-optimize-apply (form)
+ − 1081 ;; If the last arg is a literal constant, turn this into a funcall.
+ − 1082 ;; The funcall optimizer can then transform (funcall 'foo ...) -> (foo ...).
+ − 1083 (let ((fn (nth 1 form))
+ − 1084 (last (nth (1- (length form)) form))) ; I think this really is fastest
+ − 1085 (or (if (or (null last)
+ − 1086 (eq (car-safe last) 'quote))
+ − 1087 (if (listp (nth 1 last))
+ − 1088 (let ((butlast (nreverse (cdr (reverse (cdr (cdr form)))))))
+ − 1089 (nconc (list 'funcall fn) butlast
+ − 1090 (mapcar #'(lambda (x) (list 'quote x)) (nth 1 last))))
+ − 1091 (byte-compile-warn
+ − 1092 "last arg to apply can't be a literal atom: %s"
+ − 1093 (prin1-to-string last))
+ − 1094 nil))
+ − 1095 form)))
+ − 1096
+ − 1097 (put 'funcall 'byte-optimizer 'byte-optimize-funcall)
+ − 1098 (put 'apply 'byte-optimizer 'byte-optimize-apply)
+ − 1099
+ − 1100
+ − 1101 (put 'let 'byte-optimizer 'byte-optimize-letX)
+ − 1102 (put 'let* 'byte-optimizer 'byte-optimize-letX)
+ − 1103 (defun byte-optimize-letX (form)
+ − 1104 (cond ((null (nth 1 form))
+ − 1105 ;; No bindings
+ − 1106 (cons 'progn (cdr (cdr form))))
+ − 1107 ((or (nth 2 form) (nthcdr 3 form))
+ − 1108 form)
+ − 1109 ;; The body is nil
+ − 1110 ((eq (car form) 'let)
+ − 1111 (append '(progn) (mapcar 'car-safe (mapcar 'cdr-safe (nth 1 form)))
+ − 1112 '(nil)))
+ − 1113 (t
+ − 1114 (let ((binds (reverse (nth 1 form))))
+ − 1115 (list 'let* (reverse (cdr binds)) (nth 1 (car binds)) nil)))))
+ − 1116
+ − 1117
+ − 1118 (put 'nth 'byte-optimizer 'byte-optimize-nth)
+ − 1119 (defun byte-optimize-nth (form)
+ − 1120 (if (and (= (safe-length form) 3) (memq (nth 1 form) '(0 1)))
+ − 1121 (list 'car (if (zerop (nth 1 form))
+ − 1122 (nth 2 form)
+ − 1123 (list 'cdr (nth 2 form))))
+ − 1124 (byte-optimize-predicate form)))
+ − 1125
+ − 1126 (put 'nthcdr 'byte-optimizer 'byte-optimize-nthcdr)
+ − 1127 (defun byte-optimize-nthcdr (form)
+ − 1128 (if (and (= (safe-length form) 3) (not (memq (nth 1 form) '(0 1 2))))
+ − 1129 (byte-optimize-predicate form)
+ − 1130 (let ((count (nth 1 form)))
+ − 1131 (setq form (nth 2 form))
+ − 1132 (while (>= (setq count (1- count)) 0)
+ − 1133 (setq form (list 'cdr form)))
+ − 1134 form)))
444
+ − 1135
+ − 1136 (put 'concat 'byte-optimizer 'byte-optimize-concat)
+ − 1137 (defun byte-optimize-concat (form)
+ − 1138 (let ((args (cdr form))
+ − 1139 (constant t))
+ − 1140 (while (and args constant)
+ − 1141 (or (byte-compile-constp (car args))
+ − 1142 (setq constant nil))
+ − 1143 (setq args (cdr args)))
+ − 1144 (if constant
+ − 1145 (eval form)
+ − 1146 form)))
428
+ − 1147
440
+ − 1148 ;;; enumerating those functions which need not be called if the returned
428
+ − 1149 ;;; value is not used. That is, something like
+ − 1150 ;;; (progn (list (something-with-side-effects) (yow))
+ − 1151 ;;; (foo))
+ − 1152 ;;; may safely be turned into
+ − 1153 ;;; (progn (progn (something-with-side-effects) (yow))
+ − 1154 ;;; (foo))
+ − 1155 ;;; Further optimizations will turn (progn (list 1 2 3) 'foo) into 'foo.
+ − 1156
+ − 1157 ;;; I wonder if I missed any :-\)
+ − 1158 (let ((side-effect-free-fns
+ − 1159 '(% * + - / /= 1+ 1- < <= = > >= abs acos append aref ash asin atan
+ − 1160 assoc assq
+ − 1161 boundp buffer-file-name buffer-local-variables buffer-modified-p
+ − 1162 buffer-substring
+ − 1163 capitalize car-less-than-car car cdr ceiling concat
+ − 1164 ;; coordinates-in-window-p not in XEmacs
+ − 1165 copy-marker cos count-lines
+ − 1166 default-boundp default-value documentation downcase
+ − 1167 elt exp expt fboundp featurep
+ − 1168 file-directory-p file-exists-p file-locked-p file-name-absolute-p
+ − 1169 file-newer-than-file-p file-readable-p file-symlink-p file-writable-p
+ − 1170 float floor format
+ − 1171 get get-buffer get-buffer-window getenv get-file-buffer
+ − 1172 ;; hash-table functions
+ − 1173 make-hash-table copy-hash-table
+ − 1174 gethash
+ − 1175 hash-table-count
+ − 1176 hash-table-rehash-size
+ − 1177 hash-table-rehash-threshold
+ − 1178 hash-table-size
+ − 1179 hash-table-test
+ − 1180 hash-table-type
+ − 1181 ;;
+ − 1182 int-to-string
+ − 1183 length log log10 logand logb logior lognot logxor lsh
+ − 1184 marker-buffer max member memq min mod
+ − 1185 next-window nth nthcdr number-to-string
440
+ − 1186 parse-colon-path plist-get previous-window
428
+ − 1187 radians-to-degrees rassq regexp-quote reverse round
+ − 1188 sin sqrt string< string= string-equal string-lessp string-to-char
+ − 1189 string-to-int string-to-number substring symbol-plist
+ − 1190 tan upcase user-variable-p vconcat
+ − 1191 ;; XEmacs change: window-edges -> window-pixel-edges
+ − 1192 window-buffer window-dedicated-p window-pixel-edges window-height
+ − 1193 window-hscroll window-minibuffer-p window-width
+ − 1194 zerop
+ − 1195 ;; functions defined by cl
+ − 1196 oddp evenp plusp minusp
+ − 1197 abs expt signum last butlast ldiff
+ − 1198 pairlis gcd lcm
+ − 1199 isqrt floor* ceiling* truncate* round* mod* rem* subseq
440
+ − 1200 list-length getf
428
+ − 1201 ))
+ − 1202 (side-effect-and-error-free-fns
+ − 1203 '(arrayp atom
+ − 1204 bobp bolp buffer-end buffer-list buffer-size buffer-string bufferp
+ − 1205 car-safe case-table-p cdr-safe char-or-string-p char-table-p
+ − 1206 characterp commandp cons
+ − 1207 consolep console-live-p consp
+ − 1208 current-buffer
+ − 1209 ;; XEmacs: extent functions, frame-live-p, various other stuff
+ − 1210 devicep device-live-p
+ − 1211 dot dot-marker eobp eolp eq eql equal eventp extentp
+ − 1212 extent-live-p floatp framep frame-live-p
+ − 1213 get-largest-window get-lru-window
+ − 1214 hash-table-p
+ − 1215 identity ignore integerp integer-or-marker-p interactive-p
+ − 1216 invocation-directory invocation-name
444
+ − 1217 keymapp list listp
428
+ − 1218 make-marker mark mark-marker markerp memory-limit minibuffer-window
+ − 1219 ;; mouse-movement-p not in XEmacs
+ − 1220 natnump nlistp not null number-or-marker-p numberp
+ − 1221 one-window-p ;; overlayp not in XEmacs
+ − 1222 point point-marker point-min point-max processp
+ − 1223 range-table-p
+ − 1224 selected-window sequencep stringp subrp symbolp syntax-table-p
+ − 1225 user-full-name user-login-name user-original-login-name
+ − 1226 user-real-login-name user-real-uid user-uid
+ − 1227 vector vectorp
+ − 1228 window-configuration-p window-live-p windowp
+ − 1229 ;; Functions defined by cl
+ − 1230 eql floatp-safe list* subst acons equalp random-state-p
+ − 1231 copy-tree sublis
+ − 1232 )))
+ − 1233 (dolist (fn side-effect-free-fns)
+ − 1234 (put fn 'side-effect-free t))
+ − 1235 (dolist (fn side-effect-and-error-free-fns)
+ − 1236 (put fn 'side-effect-free 'error-free)))
+ − 1237
+ − 1238
+ − 1239 (defun byte-compile-splice-in-already-compiled-code (form)
+ − 1240 ;; form is (byte-code "..." [...] n)
446
+ − 1241 (if (not (memq byte-optimize '(t byte)))
428
+ − 1242 (byte-compile-normal-call form)
+ − 1243 (byte-inline-lapcode
+ − 1244 (byte-decompile-bytecode-1 (nth 1 form) (nth 2 form) t))
+ − 1245 (setq byte-compile-maxdepth (max (+ byte-compile-depth (nth 3 form))
+ − 1246 byte-compile-maxdepth))
+ − 1247 (setq byte-compile-depth (1+ byte-compile-depth))))
+ − 1248
+ − 1249 (put 'byte-code 'byte-compile 'byte-compile-splice-in-already-compiled-code)
+ − 1250
+ − 1251
+ − 1252 (defconst byte-constref-ops
+ − 1253 '(byte-constant byte-constant2 byte-varref byte-varset byte-varbind))
+ − 1254
+ − 1255 ;;; This function extracts the bitfields from variable-length opcodes.
+ − 1256 ;;; Originally defined in disass.el (which no longer uses it.)
+ − 1257
+ − 1258 (defun disassemble-offset ()
+ − 1259 "Don't call this!"
+ − 1260 ;; fetch and return the offset for the current opcode.
+ − 1261 ;; return NIL if this opcode has no offset
+ − 1262 ;; OP, PTR and BYTES are used and set dynamically
442
+ − 1263 (declare (special op ptr bytes))
428
+ − 1264 (cond ((< op byte-nth)
+ − 1265 (let ((tem (logand op 7)))
+ − 1266 (setq op (logand op 248))
+ − 1267 (cond ((eq tem 6)
+ − 1268 (setq ptr (1+ ptr)) ;offset in next byte
+ − 1269 ;; char-to-int to avoid downstream problems
+ − 1270 ;; caused by chars appearing where ints are
+ − 1271 ;; expected. In bytecode the bytes in the
+ − 1272 ;; opcode string are always interpreted as ints.
+ − 1273 (char-to-int (aref bytes ptr)))
+ − 1274 ((eq tem 7)
+ − 1275 (setq ptr (1+ ptr)) ;offset in next 2 bytes
+ − 1276 (+ (aref bytes ptr)
+ − 1277 (progn (setq ptr (1+ ptr))
+ − 1278 (lsh (aref bytes ptr) 8))))
+ − 1279 (t tem)))) ;offset was in opcode
+ − 1280 ((>= op byte-constant)
+ − 1281 (prog1 (- op byte-constant) ;offset in opcode
+ − 1282 (setq op byte-constant)))
+ − 1283 ((and (>= op byte-constant2)
+ − 1284 (<= op byte-goto-if-not-nil-else-pop))
+ − 1285 (setq ptr (1+ ptr)) ;offset in next 2 bytes
+ − 1286 (+ (aref bytes ptr)
+ − 1287 (progn (setq ptr (1+ ptr))
+ − 1288 (lsh (aref bytes ptr) 8))))
+ − 1289 ;; XEmacs: this code was here before. FSF's first comparison
+ − 1290 ;; is (>= op byte-listN). It appears that the rel-goto stuff
+ − 1291 ;; does not exist in FSF 19.30. It doesn't exist in 19.28
+ − 1292 ;; either, so I'm going to assume that this is an improvement
+ − 1293 ;; on our part and leave it in. --ben
+ − 1294 ((and (>= op byte-rel-goto)
+ − 1295 (<= op byte-insertN))
+ − 1296 (setq ptr (1+ ptr)) ;offset in next byte
+ − 1297 ;; Use char-to-int to avoid downstream problems caused by
+ − 1298 ;; chars appearing where ints are expected. In bytecode
+ − 1299 ;; the bytes in the opcode string are always interpreted as
+ − 1300 ;; ints.
+ − 1301 (char-to-int (aref bytes ptr)))))
+ − 1302
+ − 1303
+ − 1304 ;;; This de-compiler is used for inline expansion of compiled functions,
+ − 1305 ;;; and by the disassembler.
+ − 1306 ;;;
+ − 1307 ;;; This list contains numbers, which are pc values,
+ − 1308 ;;; before each instruction.
+ − 1309 (defun byte-decompile-bytecode (bytes constvec)
+ − 1310 "Turns BYTECODE into lapcode, referring to CONSTVEC."
+ − 1311 (let ((byte-compile-constants nil)
+ − 1312 (byte-compile-variables nil)
+ − 1313 (byte-compile-tag-number 0))
+ − 1314 (byte-decompile-bytecode-1 bytes constvec)))
+ − 1315
+ − 1316 ;; As byte-decompile-bytecode, but updates
+ − 1317 ;; byte-compile-{constants, variables, tag-number}.
+ − 1318 ;; If MAKE-SPLICEABLE is true, then `return' opcodes are replaced
+ − 1319 ;; with `goto's destined for the end of the code.
+ − 1320 ;; That is for use by the compiler.
+ − 1321 ;; If MAKE-SPLICEABLE is nil, we are being called for the disassembler.
+ − 1322 ;; In that case, we put a pc value into the list
+ − 1323 ;; before each insn (or its label).
+ − 1324 (defun byte-decompile-bytecode-1 (bytes constvec &optional make-spliceable)
+ − 1325 (let ((length (length bytes))
+ − 1326 (ptr 0) optr tags op offset
+ − 1327 ;; tag unused
+ − 1328 lap tmp
+ − 1329 endtag
+ − 1330 ;; (retcount 0) unused
+ − 1331 )
+ − 1332 (while (not (= ptr length))
+ − 1333 (or make-spliceable
+ − 1334 (setq lap (cons ptr lap)))
+ − 1335 (setq op (aref bytes ptr)
+ − 1336 optr ptr
+ − 1337 offset (disassemble-offset)) ; this does dynamic-scope magic
+ − 1338 (setq op (aref byte-code-vector op))
+ − 1339 ;; XEmacs: the next line in FSF 19.30 reads
+ − 1340 ;; (cond ((memq op byte-goto-ops)
+ − 1341 ;; see the comment above about byte-rel-goto in XEmacs.
+ − 1342 (cond ((or (memq op byte-goto-ops)
+ − 1343 (cond ((memq op byte-rel-goto-ops)
+ − 1344 (setq op (aref byte-code-vector
+ − 1345 (- (symbol-value op)
+ − 1346 (- byte-rel-goto byte-goto))))
+ − 1347 (setq offset (+ ptr (- offset 127)))
+ − 1348 t)))
+ − 1349 ;; it's a pc
+ − 1350 (setq offset
+ − 1351 (cdr (or (assq offset tags)
+ − 1352 (car (setq tags
+ − 1353 (cons (cons offset
+ − 1354 (byte-compile-make-tag))
+ − 1355 tags)))))))
+ − 1356 ((cond ((eq op 'byte-constant2) (setq op 'byte-constant) t)
+ − 1357 ((memq op byte-constref-ops)))
+ − 1358 (setq tmp (aref constvec offset)
+ − 1359 offset (if (eq op 'byte-constant)
+ − 1360 (byte-compile-get-constant tmp)
+ − 1361 (or (assq tmp byte-compile-variables)
+ − 1362 (car (setq byte-compile-variables
+ − 1363 (cons (list tmp)
+ − 1364 byte-compile-variables)))))))
+ − 1365 ((and make-spliceable
+ − 1366 (eq op 'byte-return))
+ − 1367 (if (= ptr (1- length))
+ − 1368 (setq op nil)
+ − 1369 (setq offset (or endtag (setq endtag (byte-compile-make-tag)))
+ − 1370 op 'byte-goto))))
+ − 1371 ;; lap = ( [ (pc . (op . arg)) ]* )
+ − 1372 (setq lap (cons (cons optr (cons op (or offset 0)))
+ − 1373 lap))
+ − 1374 (setq ptr (1+ ptr)))
+ − 1375 ;; take off the dummy nil op that we replaced a trailing "return" with.
+ − 1376 (let ((rest lap))
+ − 1377 (while rest
+ − 1378 (cond ((numberp (car rest)))
+ − 1379 ((setq tmp (assq (car (car rest)) tags))
+ − 1380 ;; this addr is jumped to
+ − 1381 (setcdr rest (cons (cons nil (cdr tmp))
+ − 1382 (cdr rest)))
+ − 1383 (setq tags (delq tmp tags))
+ − 1384 (setq rest (cdr rest))))
+ − 1385 (setq rest (cdr rest))))
+ − 1386 (if tags (error "optimizer error: missed tags %s" tags))
+ − 1387 (if (null (car (cdr (car lap))))
+ − 1388 (setq lap (cdr lap)))
+ − 1389 (if endtag
+ − 1390 (setq lap (cons (cons nil endtag) lap)))
+ − 1391 ;; remove addrs, lap = ( [ (op . arg) | (TAG tagno) ]* )
+ − 1392 (mapcar #'(lambda (elt) (if (numberp elt) elt (cdr elt)))
+ − 1393 (nreverse lap))))
+ − 1394
+ − 1395
+ − 1396 ;;; peephole optimizer
+ − 1397
+ − 1398 (defconst byte-tagref-ops (cons 'TAG byte-goto-ops))
+ − 1399
+ − 1400 (defconst byte-conditional-ops
+ − 1401 '(byte-goto-if-nil byte-goto-if-not-nil byte-goto-if-nil-else-pop
+ − 1402 byte-goto-if-not-nil-else-pop))
+ − 1403
+ − 1404 (defconst byte-after-unbind-ops
+ − 1405 '(byte-constant byte-dup
+ − 1406 byte-symbolp byte-consp byte-stringp byte-listp byte-numberp byte-integerp
444
+ − 1407 byte-eq byte-not
428
+ − 1408 byte-cons byte-list1 byte-list2 ; byte-list3 byte-list4
+ − 1409 byte-interactive-p)
+ − 1410 ;; How about other side-effect-free-ops? Is it safe to move an
+ − 1411 ;; error invocation (such as from nth) out of an unwind-protect?
444
+ − 1412 ;; No, it is not, because the unwind-protect forms can alter
+ − 1413 ;; the inside of the object to which nth would apply.
+ − 1414 ;; For the same reason, byte-equal was deleted from this list.
428
+ − 1415 "Byte-codes that can be moved past an unbind.")
+ − 1416
+ − 1417 (defconst byte-compile-side-effect-and-error-free-ops
+ − 1418 '(byte-constant byte-dup byte-symbolp byte-consp byte-stringp byte-listp
+ − 1419 byte-integerp byte-numberp byte-eq byte-equal byte-not byte-car-safe
+ − 1420 byte-cdr-safe byte-cons byte-list1 byte-list2 byte-point byte-point-max
+ − 1421 byte-point-min byte-following-char byte-preceding-char
+ − 1422 byte-current-column byte-eolp byte-eobp byte-bolp byte-bobp
+ − 1423 byte-current-buffer byte-interactive-p))
+ − 1424
+ − 1425 (defconst byte-compile-side-effect-free-ops
440
+ − 1426 (nconc
428
+ − 1427 '(byte-varref byte-nth byte-memq byte-car byte-cdr byte-length byte-aref
+ − 1428 byte-symbol-value byte-get byte-concat2 byte-concat3 byte-sub1 byte-add1
+ − 1429 byte-eqlsign byte-gtr byte-lss byte-leq byte-geq byte-diff byte-negate
+ − 1430 byte-plus byte-max byte-min byte-mult byte-char-after byte-char-syntax
+ − 1431 byte-buffer-substring byte-string= byte-string< byte-nthcdr byte-elt
+ − 1432 byte-member byte-assq byte-quo byte-rem)
+ − 1433 byte-compile-side-effect-and-error-free-ops))
+ − 1434
+ − 1435 ;;; This piece of shit is because of the way DEFVAR_BOOL() variables work.
+ − 1436 ;;; Consider the code
+ − 1437 ;;;
+ − 1438 ;;; (defun foo (flag)
+ − 1439 ;;; (let ((old-pop-ups pop-up-windows)
+ − 1440 ;;; (pop-up-windows flag))
+ − 1441 ;;; (cond ((not (eq pop-up-windows old-pop-ups))
+ − 1442 ;;; (setq old-pop-ups pop-up-windows)
+ − 1443 ;;; ...))))
+ − 1444 ;;;
+ − 1445 ;;; Uncompiled, old-pop-ups will always be set to nil or t, even if FLAG is
+ − 1446 ;;; something else. But if we optimize
+ − 1447 ;;;
+ − 1448 ;;; varref flag
+ − 1449 ;;; varbind pop-up-windows
+ − 1450 ;;; varref pop-up-windows
+ − 1451 ;;; not
+ − 1452 ;;; to
+ − 1453 ;;; varref flag
+ − 1454 ;;; dup
+ − 1455 ;;; varbind pop-up-windows
+ − 1456 ;;; not
+ − 1457 ;;;
440
+ − 1458 ;;; we break the program, because it will appear that pop-up-windows and
428
+ − 1459 ;;; old-pop-ups are not EQ when really they are. So we have to know what
+ − 1460 ;;; the BOOL variables are, and not perform this optimization on them.
+ − 1461 ;;;
+ − 1462
+ − 1463 ;;; This used to hold a large list of boolean variables, which had to
+ − 1464 ;;; be updated every time a new DEFVAR_BOOL is added, making it very
+ − 1465 ;;; hard to maintain. Such a list is not necessary under XEmacs,
+ − 1466 ;;; where we can use `built-in-variable-type' to query for boolean
+ − 1467 ;;; variables.
+ − 1468
+ − 1469 ;(defconst byte-boolean-vars
+ − 1470 ; '(abbrev-all-caps purify-flag find-file-compare-truenames
+ − 1471 ; find-file-use-truenames delete-auto-save-files byte-metering-on
+ − 1472 ; x-seppuku-on-epipe zmacs-regions zmacs-region-active-p
+ − 1473 ; zmacs-region-stays atomic-extent-goto-char-p
+ − 1474 ; suppress-early-error-handler-backtrace noninteractive
+ − 1475 ; inhibit-early-packages inhibit-autoloads debug-paths
+ − 1476 ; inhibit-site-lisp debug-on-quit debug-on-next-call
+ − 1477 ; modifier-keys-are-sticky x-allow-sendevents
+ − 1478 ; mswindows-dynamic-frame-resize focus-follows-mouse
+ − 1479 ; inhibit-input-event-recording enable-multibyte-characters
+ − 1480 ; disable-auto-save-when-buffer-shrinks
+ − 1481 ; allow-deletion-of-last-visible-frame indent-tabs-mode
+ − 1482 ; load-in-progress load-warn-when-source-newer
+ − 1483 ; load-warn-when-source-only load-ignore-elc-files
+ − 1484 ; load-force-doc-strings fail-on-bucky-bit-character-escapes
+ − 1485 ; popup-menu-titles menubar-show-keybindings completion-ignore-case
+ − 1486 ; canna-empty-info canna-through-info canna-underline
+ − 1487 ; canna-inhibit-hankakukana enable-multibyte-characters
+ − 1488 ; re-short-flag x-handle-non-fully-specified-fonts
+ − 1489 ; print-escape-newlines print-readably delete-exited-processes
+ − 1490 ; windowed-process-io visible-bell no-redraw-on-reenter
+ − 1491 ; cursor-in-echo-area inhibit-warning-display
+ − 1492 ; column-number-start-at-one parse-sexp-ignore-comments
+ − 1493 ; words-include-escapes scroll-on-clipped-lines)
+ − 1494 ; "DEFVAR_BOOL variables. Giving these any non-nil value sets them to t.
+ − 1495 ;If this does not enumerate all DEFVAR_BOOL variables, the byte-optimizer
+ − 1496 ;may generate incorrect code.")
+ − 1497
+ − 1498 (defun byte-optimize-lapcode (lap &optional for-effect)
+ − 1499 "Simple peephole optimizer. LAP is both modified and returned."
442
+ − 1500 (let (lap0
+ − 1501 lap1
+ − 1502 lap2
+ − 1503 variable-frequency
428
+ − 1504 (keep-going 'first-time)
+ − 1505 (add-depth 0)
+ − 1506 rest tmp tmp2 tmp3
+ − 1507 (side-effect-free (if byte-compile-delete-errors
+ − 1508 byte-compile-side-effect-free-ops
+ − 1509 byte-compile-side-effect-and-error-free-ops)))
+ − 1510 (while keep-going
+ − 1511 (or (eq keep-going 'first-time)
+ − 1512 (byte-compile-log-lap " ---- next pass"))
+ − 1513 (setq rest lap
+ − 1514 keep-going nil)
+ − 1515 (while rest
+ − 1516 (setq lap0 (car rest)
+ − 1517 lap1 (nth 1 rest)
+ − 1518 lap2 (nth 2 rest))
+ − 1519
+ − 1520 ;; You may notice that sequences like "dup varset discard" are
+ − 1521 ;; optimized but sequences like "dup varset TAG1: discard" are not.
+ − 1522 ;; You may be tempted to change this; resist that temptation.
+ − 1523 (cond ;;
+ − 1524 ;; <side-effect-free> pop --> <deleted>
+ − 1525 ;; ...including:
+ − 1526 ;; const-X pop --> <deleted>
+ − 1527 ;; varref-X pop --> <deleted>
+ − 1528 ;; dup pop --> <deleted>
+ − 1529 ;;
+ − 1530 ((and (eq 'byte-discard (car lap1))
+ − 1531 (memq (car lap0) side-effect-free))
+ − 1532 (setq keep-going t)
+ − 1533 (setq tmp (aref byte-stack+-info (symbol-value (car lap0))))
+ − 1534 (setq rest (cdr rest))
+ − 1535 (cond ((= tmp 1)
+ − 1536 (byte-compile-log-lap
+ − 1537 " %s discard\t-->\t<deleted>" lap0)
+ − 1538 (setq lap (delq lap0 (delq lap1 lap))))
+ − 1539 ((= tmp 0)
+ − 1540 (byte-compile-log-lap
+ − 1541 " %s discard\t-->\t<deleted> discard" lap0)
+ − 1542 (setq lap (delq lap0 lap)))
+ − 1543 ((= tmp -1)
+ − 1544 (byte-compile-log-lap
+ − 1545 " %s discard\t-->\tdiscard discard" lap0)
+ − 1546 (setcar lap0 'byte-discard)
+ − 1547 (setcdr lap0 0))
+ − 1548 ((error "Optimizer error: too much on the stack"))))
+ − 1549 ;;
+ − 1550 ;; goto*-X X: --> X:
+ − 1551 ;;
+ − 1552 ((and (memq (car lap0) byte-goto-ops)
+ − 1553 (eq (cdr lap0) lap1))
+ − 1554 (cond ((eq (car lap0) 'byte-goto)
+ − 1555 (setq lap (delq lap0 lap))
+ − 1556 (setq tmp "<deleted>"))
+ − 1557 ((memq (car lap0) byte-goto-always-pop-ops)
+ − 1558 (setcar lap0 (setq tmp 'byte-discard))
+ − 1559 (setcdr lap0 0))
+ − 1560 ((error "Depth conflict at tag %d" (nth 2 lap0))))
+ − 1561 (and (memq byte-optimize-log '(t byte))
+ − 1562 (byte-compile-log " (goto %s) %s:\t-->\t%s %s:"
+ − 1563 (nth 1 lap1) (nth 1 lap1)
+ − 1564 tmp (nth 1 lap1)))
+ − 1565 (setq keep-going t))
+ − 1566 ;;
+ − 1567 ;; varset-X varref-X --> dup varset-X
+ − 1568 ;; varbind-X varref-X --> dup varbind-X
+ − 1569 ;; const/dup varset-X varref-X --> const/dup varset-X const/dup
+ − 1570 ;; const/dup varbind-X varref-X --> const/dup varbind-X const/dup
+ − 1571 ;; The latter two can enable other optimizations.
+ − 1572 ;;
+ − 1573 ((and (eq 'byte-varref (car lap2))
+ − 1574 (eq (cdr lap1) (cdr lap2))
+ − 1575 (memq (car lap1) '(byte-varset byte-varbind)))
+ − 1576 (if (and (setq tmp (eq (built-in-variable-type (car (cdr lap2)))
+ − 1577 'boolean))
+ − 1578 (not (eq (car lap0) 'byte-constant)))
+ − 1579 nil
+ − 1580 (setq keep-going t)
+ − 1581 (if (memq (car lap0) '(byte-constant byte-dup))
+ − 1582 (progn
+ − 1583 (setq tmp (if (or (not tmp)
+ − 1584 (memq (car (cdr lap0)) '(nil t)))
+ − 1585 (cdr lap0)
+ − 1586 (byte-compile-get-constant t)))
+ − 1587 (byte-compile-log-lap " %s %s %s\t-->\t%s %s %s"
+ − 1588 lap0 lap1 lap2 lap0 lap1
+ − 1589 (cons (car lap0) tmp))
+ − 1590 (setcar lap2 (car lap0))
+ − 1591 (setcdr lap2 tmp))
+ − 1592 (byte-compile-log-lap " %s %s\t-->\tdup %s" lap1 lap2 lap1)
+ − 1593 (setcar lap2 (car lap1))
+ − 1594 (setcar lap1 'byte-dup)
+ − 1595 (setcdr lap1 0)
+ − 1596 ;; The stack depth gets locally increased, so we will
+ − 1597 ;; increase maxdepth in case depth = maxdepth here.
+ − 1598 ;; This can cause the third argument to byte-code to
+ − 1599 ;; be larger than necessary.
+ − 1600 (setq add-depth 1))))
+ − 1601 ;;
+ − 1602 ;; dup varset-X discard --> varset-X
+ − 1603 ;; dup varbind-X discard --> varbind-X
+ − 1604 ;; (the varbind variant can emerge from other optimizations)
+ − 1605 ;;
+ − 1606 ((and (eq 'byte-dup (car lap0))
+ − 1607 (eq 'byte-discard (car lap2))
+ − 1608 (memq (car lap1) '(byte-varset byte-varbind)))
+ − 1609 (byte-compile-log-lap " dup %s discard\t-->\t%s" lap1 lap1)
+ − 1610 (setq keep-going t
+ − 1611 rest (cdr rest))
+ − 1612 (setq lap (delq lap0 (delq lap2 lap))))
+ − 1613 ;;
+ − 1614 ;; not goto-X-if-nil --> goto-X-if-non-nil
+ − 1615 ;; not goto-X-if-non-nil --> goto-X-if-nil
+ − 1616 ;;
+ − 1617 ;; it is wrong to do the same thing for the -else-pop variants.
+ − 1618 ;;
+ − 1619 ((and (eq 'byte-not (car lap0))
+ − 1620 (or (eq 'byte-goto-if-nil (car lap1))
+ − 1621 (eq 'byte-goto-if-not-nil (car lap1))))
+ − 1622 (byte-compile-log-lap " not %s\t-->\t%s"
+ − 1623 lap1
+ − 1624 (cons
+ − 1625 (if (eq (car lap1) 'byte-goto-if-nil)
+ − 1626 'byte-goto-if-not-nil
+ − 1627 'byte-goto-if-nil)
+ − 1628 (cdr lap1)))
+ − 1629 (setcar lap1 (if (eq (car lap1) 'byte-goto-if-nil)
+ − 1630 'byte-goto-if-not-nil
+ − 1631 'byte-goto-if-nil))
+ − 1632 (setq lap (delq lap0 lap))
+ − 1633 (setq keep-going t))
+ − 1634 ;;
+ − 1635 ;; goto-X-if-nil goto-Y X: --> goto-Y-if-non-nil X:
+ − 1636 ;; goto-X-if-non-nil goto-Y X: --> goto-Y-if-nil X:
+ − 1637 ;;
+ − 1638 ;; it is wrong to do the same thing for the -else-pop variants.
440
+ − 1639 ;;
428
+ − 1640 ((and (or (eq 'byte-goto-if-nil (car lap0))
+ − 1641 (eq 'byte-goto-if-not-nil (car lap0))) ; gotoX
+ − 1642 (eq 'byte-goto (car lap1)) ; gotoY
+ − 1643 (eq (cdr lap0) lap2)) ; TAG X
+ − 1644 (let ((inverse (if (eq 'byte-goto-if-nil (car lap0))
+ − 1645 'byte-goto-if-not-nil 'byte-goto-if-nil)))
+ − 1646 (byte-compile-log-lap " %s %s %s:\t-->\t%s %s:"
+ − 1647 lap0 lap1 lap2
+ − 1648 (cons inverse (cdr lap1)) lap2)
+ − 1649 (setq lap (delq lap0 lap))
+ − 1650 (setcar lap1 inverse)
+ − 1651 (setq keep-going t)))
+ − 1652 ;;
+ − 1653 ;; const goto-if-* --> whatever
+ − 1654 ;;
+ − 1655 ((and (eq 'byte-constant (car lap0))
+ − 1656 (memq (car lap1) byte-conditional-ops))
+ − 1657 (cond ((if (or (eq (car lap1) 'byte-goto-if-nil)
+ − 1658 (eq (car lap1) 'byte-goto-if-nil-else-pop))
+ − 1659 (car (cdr lap0))
+ − 1660 (not (car (cdr lap0))))
+ − 1661 (byte-compile-log-lap " %s %s\t-->\t<deleted>"
+ − 1662 lap0 lap1)
+ − 1663 (setq rest (cdr rest)
+ − 1664 lap (delq lap0 (delq lap1 lap))))
+ − 1665 (t
+ − 1666 (if (memq (car lap1) byte-goto-always-pop-ops)
+ − 1667 (progn
+ − 1668 (byte-compile-log-lap " %s %s\t-->\t%s"
+ − 1669 lap0 lap1 (cons 'byte-goto (cdr lap1)))
+ − 1670 (setq lap (delq lap0 lap)))
+ − 1671 (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1
+ − 1672 (cons 'byte-goto (cdr lap1))))
+ − 1673 (setcar lap1 'byte-goto)))
+ − 1674 (setq keep-going t))
+ − 1675 ;;
+ − 1676 ;; varref-X varref-X --> varref-X dup
+ − 1677 ;; varref-X [dup ...] varref-X --> varref-X [dup ...] dup
+ − 1678 ;; We don't optimize the const-X variations on this here,
+ − 1679 ;; because that would inhibit some goto optimizations; we
+ − 1680 ;; optimize the const-X case after all other optimizations.
+ − 1681 ;;
+ − 1682 ((and (eq 'byte-varref (car lap0))
+ − 1683 (progn
+ − 1684 (setq tmp (cdr rest))
+ − 1685 (while (eq (car (car tmp)) 'byte-dup)
+ − 1686 (setq tmp (cdr tmp)))
+ − 1687 t)
+ − 1688 (eq (cdr lap0) (cdr (car tmp)))
+ − 1689 (eq 'byte-varref (car (car tmp))))
+ − 1690 (if (memq byte-optimize-log '(t byte))
+ − 1691 (let ((str ""))
+ − 1692 (setq tmp2 (cdr rest))
+ − 1693 (while (not (eq tmp tmp2))
+ − 1694 (setq tmp2 (cdr tmp2)
+ − 1695 str (concat str " dup")))
+ − 1696 (byte-compile-log-lap " %s%s %s\t-->\t%s%s dup"
+ − 1697 lap0 str lap0 lap0 str)))
+ − 1698 (setq keep-going t)
+ − 1699 (setcar (car tmp) 'byte-dup)
+ − 1700 (setcdr (car tmp) 0)
+ − 1701 (setq rest tmp))
+ − 1702 ;;
+ − 1703 ;; TAG1: TAG2: --> TAG1: <deleted>
+ − 1704 ;; (and other references to TAG2 are replaced with TAG1)
+ − 1705 ;;
+ − 1706 ((and (eq (car lap0) 'TAG)
+ − 1707 (eq (car lap1) 'TAG))
+ − 1708 (and (memq byte-optimize-log '(t byte))
+ − 1709 (byte-compile-log " adjacent tags %d and %d merged"
+ − 1710 (nth 1 lap1) (nth 1 lap0)))
+ − 1711 (setq tmp3 lap)
+ − 1712 (while (setq tmp2 (rassq lap0 tmp3))
+ − 1713 (setcdr tmp2 lap1)
+ − 1714 (setq tmp3 (cdr (memq tmp2 tmp3))))
+ − 1715 (setq lap (delq lap0 lap)
+ − 1716 keep-going t))
+ − 1717 ;;
+ − 1718 ;; unused-TAG: --> <deleted>
+ − 1719 ;;
+ − 1720 ((and (eq 'TAG (car lap0))
+ − 1721 (not (rassq lap0 lap)))
+ − 1722 (and (memq byte-optimize-log '(t byte))
+ − 1723 (byte-compile-log " unused tag %d removed" (nth 1 lap0)))
+ − 1724 (setq lap (delq lap0 lap)
+ − 1725 keep-going t))
+ − 1726 ;;
+ − 1727 ;; goto ... --> goto <delete until TAG or end>
+ − 1728 ;; return ... --> return <delete until TAG or end>
+ − 1729 ;;
+ − 1730 ((and (memq (car lap0) '(byte-goto byte-return))
+ − 1731 (not (memq (car lap1) '(TAG nil))))
+ − 1732 (setq tmp rest)
+ − 1733 (let ((i 0)
+ − 1734 (opt-p (memq byte-optimize-log '(t lap)))
+ − 1735 str deleted)
+ − 1736 (while (and (setq tmp (cdr tmp))
+ − 1737 (not (eq 'TAG (car (car tmp)))))
+ − 1738 (if opt-p (setq deleted (cons (car tmp) deleted)
+ − 1739 str (concat str " %s")
+ − 1740 i (1+ i))))
+ − 1741 (if opt-p
440
+ − 1742 (let ((tagstr
428
+ − 1743 (if (eq 'TAG (car (car tmp)))
+ − 1744 (format "%d:" (car (cdr (car tmp))))
+ − 1745 (or (car tmp) ""))))
+ − 1746 (if (< i 6)
+ − 1747 (apply 'byte-compile-log-lap-1
+ − 1748 (concat " %s" str
+ − 1749 " %s\t-->\t%s <deleted> %s")
+ − 1750 lap0
+ − 1751 (nconc (nreverse deleted)
+ − 1752 (list tagstr lap0 tagstr)))
+ − 1753 (byte-compile-log-lap
+ − 1754 " %s <%d unreachable op%s> %s\t-->\t%s <deleted> %s"
+ − 1755 lap0 i (if (= i 1) "" "s")
+ − 1756 tagstr lap0 tagstr))))
+ − 1757 (rplacd rest tmp))
+ − 1758 (setq keep-going t))
+ − 1759 ;;
+ − 1760 ;; <safe-op> unbind --> unbind <safe-op>
+ − 1761 ;; (this may enable other optimizations.)
+ − 1762 ;;
+ − 1763 ((and (eq 'byte-unbind (car lap1))
+ − 1764 (memq (car lap0) byte-after-unbind-ops))
+ − 1765 (byte-compile-log-lap " %s %s\t-->\t%s %s" lap0 lap1 lap1 lap0)
+ − 1766 (setcar rest lap1)
+ − 1767 (setcar (cdr rest) lap0)
+ − 1768 (setq keep-going t))
+ − 1769 ;;
+ − 1770 ;; varbind-X unbind-N --> discard unbind-(N-1)
+ − 1771 ;; save-excursion unbind-N --> unbind-(N-1)
+ − 1772 ;; save-restriction unbind-N --> unbind-(N-1)
+ − 1773 ;;
+ − 1774 ((and (eq 'byte-unbind (car lap1))
+ − 1775 (memq (car lap0) '(byte-varbind byte-save-excursion
+ − 1776 byte-save-restriction))
+ − 1777 (< 0 (cdr lap1)))
+ − 1778 (if (zerop (setcdr lap1 (1- (cdr lap1))))
+ − 1779 (delq lap1 rest))
+ − 1780 (if (eq (car lap0) 'byte-varbind)
+ − 1781 (setcar rest (cons 'byte-discard 0))
+ − 1782 (setq lap (delq lap0 lap)))
+ − 1783 (byte-compile-log-lap " %s %s\t-->\t%s %s"
+ − 1784 lap0 (cons (car lap1) (1+ (cdr lap1)))
+ − 1785 (if (eq (car lap0) 'byte-varbind)
+ − 1786 (car rest)
+ − 1787 (car (cdr rest)))
+ − 1788 (if (and (/= 0 (cdr lap1))
+ − 1789 (eq (car lap0) 'byte-varbind))
+ − 1790 (car (cdr rest))
+ − 1791 ""))
+ − 1792 (setq keep-going t))
+ − 1793 ;;
+ − 1794 ;; goto*-X ... X: goto-Y --> goto*-Y
+ − 1795 ;; goto-X ... X: return --> return
+ − 1796 ;;
+ − 1797 ((and (memq (car lap0) byte-goto-ops)
+ − 1798 (memq (car (setq tmp (nth 1 (memq (cdr lap0) lap))))
+ − 1799 '(byte-goto byte-return)))
+ − 1800 (cond ((and (not (eq tmp lap0))
+ − 1801 (or (eq (car lap0) 'byte-goto)
+ − 1802 (eq (car tmp) 'byte-goto)))
+ − 1803 (byte-compile-log-lap " %s [%s]\t-->\t%s"
+ − 1804 (car lap0) tmp tmp)
+ − 1805 (if (eq (car tmp) 'byte-return)
+ − 1806 (setcar lap0 'byte-return))
+ − 1807 (setcdr lap0 (cdr tmp))
+ − 1808 (setq keep-going t))))
+ − 1809 ;;
+ − 1810 ;; goto-*-else-pop X ... X: goto-if-* --> whatever
+ − 1811 ;; goto-*-else-pop X ... X: discard --> whatever
+ − 1812 ;;
+ − 1813 ((and (memq (car lap0) '(byte-goto-if-nil-else-pop
+ − 1814 byte-goto-if-not-nil-else-pop))
+ − 1815 (memq (car (car (setq tmp (cdr (memq (cdr lap0) lap)))))
+ − 1816 (eval-when-compile
+ − 1817 (cons 'byte-discard byte-conditional-ops)))
+ − 1818 (not (eq lap0 (car tmp))))
+ − 1819 (setq tmp2 (car tmp))
+ − 1820 (setq tmp3 (assq (car lap0) '((byte-goto-if-nil-else-pop
+ − 1821 byte-goto-if-nil)
+ − 1822 (byte-goto-if-not-nil-else-pop
+ − 1823 byte-goto-if-not-nil))))
+ − 1824 (if (memq (car tmp2) tmp3)
+ − 1825 (progn (setcar lap0 (car tmp2))
+ − 1826 (setcdr lap0 (cdr tmp2))
+ − 1827 (byte-compile-log-lap " %s-else-pop [%s]\t-->\t%s"
+ − 1828 (car lap0) tmp2 lap0))
+ − 1829 ;; Get rid of the -else-pop's and jump one step further.
+ − 1830 (or (eq 'TAG (car (nth 1 tmp)))
+ − 1831 (setcdr tmp (cons (byte-compile-make-tag)
+ − 1832 (cdr tmp))))
+ − 1833 (byte-compile-log-lap " %s [%s]\t-->\t%s <skip>"
+ − 1834 (car lap0) tmp2 (nth 1 tmp3))
+ − 1835 (setcar lap0 (nth 1 tmp3))
+ − 1836 (setcdr lap0 (nth 1 tmp)))
+ − 1837 (setq keep-going t))
+ − 1838 ;;
+ − 1839 ;; const goto-X ... X: goto-if-* --> whatever
+ − 1840 ;; const goto-X ... X: discard --> whatever
+ − 1841 ;;
+ − 1842 ((and (eq (car lap0) 'byte-constant)
+ − 1843 (eq (car lap1) 'byte-goto)
+ − 1844 (memq (car (car (setq tmp (cdr (memq (cdr lap1) lap)))))
+ − 1845 (eval-when-compile
+ − 1846 (cons 'byte-discard byte-conditional-ops)))
+ − 1847 (not (eq lap1 (car tmp))))
+ − 1848 (setq tmp2 (car tmp))
+ − 1849 (cond ((memq (car tmp2)
+ − 1850 (if (null (car (cdr lap0)))
+ − 1851 '(byte-goto-if-nil byte-goto-if-nil-else-pop)
+ − 1852 '(byte-goto-if-not-nil
+ − 1853 byte-goto-if-not-nil-else-pop)))
+ − 1854 (byte-compile-log-lap " %s goto [%s]\t-->\t%s %s"
+ − 1855 lap0 tmp2 lap0 tmp2)
+ − 1856 (setcar lap1 (car tmp2))
+ − 1857 (setcdr lap1 (cdr tmp2))
+ − 1858 ;; Let next step fix the (const,goto-if*) sequence.
+ − 1859 (setq rest (cons nil rest)))
+ − 1860 (t
+ − 1861 ;; Jump one step further
+ − 1862 (byte-compile-log-lap
+ − 1863 " %s goto [%s]\t-->\t<deleted> goto <skip>"
+ − 1864 lap0 tmp2)
+ − 1865 (or (eq 'TAG (car (nth 1 tmp)))
+ − 1866 (setcdr tmp (cons (byte-compile-make-tag)
+ − 1867 (cdr tmp))))
+ − 1868 (setcdr lap1 (car (cdr tmp)))
+ − 1869 (setq lap (delq lap0 lap))))
+ − 1870 (setq keep-going t))
+ − 1871 ;;
+ − 1872 ;; X: varref-Y ... varset-Y goto-X -->
+ − 1873 ;; X: varref-Y Z: ... dup varset-Y goto-Z
+ − 1874 ;; (varset-X goto-BACK, BACK: varref-X --> copy the varref down.)
+ − 1875 ;; (This is so usual for while loops that it is worth handling).
+ − 1876 ;;
+ − 1877 ((and (eq (car lap1) 'byte-varset)
+ − 1878 (eq (car lap2) 'byte-goto)
+ − 1879 (not (memq (cdr lap2) rest)) ;Backwards jump
+ − 1880 (eq (car (car (setq tmp (cdr (memq (cdr lap2) lap)))))
+ − 1881 'byte-varref)
+ − 1882 (eq (cdr (car tmp)) (cdr lap1))
+ − 1883 (not (eq (built-in-variable-type (car (cdr lap1)))
+ − 1884 'boolean)))
+ − 1885 ;;(byte-compile-log-lap " Pulled %s to end of loop" (car tmp))
+ − 1886 (let ((newtag (byte-compile-make-tag)))
+ − 1887 (byte-compile-log-lap
+ − 1888 " %s: %s ... %s %s\t-->\t%s: %s %s: ... %s %s %s"
+ − 1889 (nth 1 (cdr lap2)) (car tmp)
+ − 1890 lap1 lap2
+ − 1891 (nth 1 (cdr lap2)) (car tmp)
+ − 1892 (nth 1 newtag) 'byte-dup lap1
+ − 1893 (cons 'byte-goto newtag)
+ − 1894 )
+ − 1895 (setcdr rest (cons (cons 'byte-dup 0) (cdr rest)))
+ − 1896 (setcdr tmp (cons (setcdr lap2 newtag) (cdr tmp))))
+ − 1897 (setq add-depth 1)
+ − 1898 (setq keep-going t))
+ − 1899 ;;
+ − 1900 ;; goto-X Y: ... X: goto-if*-Y --> goto-if-not-*-X+1 Y:
+ − 1901 ;; (This can pull the loop test to the end of the loop)
+ − 1902 ;;
+ − 1903 ((and (eq (car lap0) 'byte-goto)
+ − 1904 (eq (car lap1) 'TAG)
+ − 1905 (eq lap1
+ − 1906 (cdr (car (setq tmp (cdr (memq (cdr lap0) lap))))))
+ − 1907 (memq (car (car tmp))
+ − 1908 '(byte-goto byte-goto-if-nil byte-goto-if-not-nil
+ − 1909 byte-goto-if-nil-else-pop)))
+ − 1910 ;; (byte-compile-log-lap " %s %s, %s %s --> moved conditional"
+ − 1911 ;; lap0 lap1 (cdr lap0) (car tmp))
+ − 1912 (let ((newtag (byte-compile-make-tag)))
+ − 1913 (byte-compile-log-lap
+ − 1914 "%s %s: ... %s: %s\t-->\t%s ... %s:"
+ − 1915 lap0 (nth 1 lap1) (nth 1 (cdr lap0)) (car tmp)
+ − 1916 (cons (cdr (assq (car (car tmp))
+ − 1917 '((byte-goto-if-nil . byte-goto-if-not-nil)
+ − 1918 (byte-goto-if-not-nil . byte-goto-if-nil)
+ − 1919 (byte-goto-if-nil-else-pop .
+ − 1920 byte-goto-if-not-nil-else-pop)
+ − 1921 (byte-goto-if-not-nil-else-pop .
+ − 1922 byte-goto-if-nil-else-pop))))
+ − 1923 newtag)
440
+ − 1924
428
+ − 1925 (nth 1 newtag)
+ − 1926 )
+ − 1927 (setcdr tmp (cons (setcdr lap0 newtag) (cdr tmp)))
+ − 1928 (if (eq (car (car tmp)) 'byte-goto-if-nil-else-pop)
+ − 1929 ;; We can handle this case but not the -if-not-nil case,
+ − 1930 ;; because we won't know which non-nil constant to push.
+ − 1931 (setcdr rest (cons (cons 'byte-constant
+ − 1932 (byte-compile-get-constant nil))
+ − 1933 (cdr rest))))
+ − 1934 (setcar lap0 (nth 1 (memq (car (car tmp))
+ − 1935 '(byte-goto-if-nil-else-pop
+ − 1936 byte-goto-if-not-nil
+ − 1937 byte-goto-if-nil
+ − 1938 byte-goto-if-not-nil
+ − 1939 byte-goto byte-goto))))
+ − 1940 )
+ − 1941 (setq keep-going t))
+ − 1942 )
+ − 1943 (setq rest (cdr rest)))
+ − 1944 )
+ − 1945 ;; Cleanup stage:
+ − 1946 ;; Rebuild byte-compile-constants / byte-compile-variables.
+ − 1947 ;; Simple optimizations that would inhibit other optimizations if they
+ − 1948 ;; were done in the optimizing loop, and optimizations which there is no
442
+ − 1949 ;; need to do more than once.
428
+ − 1950 (setq byte-compile-constants nil
442
+ − 1951 byte-compile-variables nil
+ − 1952 variable-frequency (make-hash-table :test 'eq))
428
+ − 1953 (setq rest lap)
+ − 1954 (while rest
+ − 1955 (setq lap0 (car rest)
+ − 1956 lap1 (nth 1 rest))
442
+ − 1957 (case (car lap0)
+ − 1958 ((byte-varref byte-varset byte-varbind)
+ − 1959 (incf (gethash (cdr lap0) variable-frequency 0))
+ − 1960 (unless (memq (cdr lap0) byte-compile-variables)
+ − 1961 (push (cdr lap0) byte-compile-variables)))
+ − 1962 ((byte-constant)
+ − 1963 (unless (memq (cdr lap0) byte-compile-constants)
+ − 1964 (push (cdr lap0) byte-compile-constants))))
428
+ − 1965 (cond (;;
442
+ − 1966 ;; const-C varset-X const-C --> const-C dup varset-X
428
+ − 1967 ;; const-C varbind-X const-C --> const-C dup varbind-X
+ − 1968 ;;
+ − 1969 (and (eq (car lap0) 'byte-constant)
+ − 1970 (eq (car (nth 2 rest)) 'byte-constant)
442
+ − 1971 (eq (cdr lap0) (cdr (nth 2 rest)))
428
+ − 1972 (memq (car lap1) '(byte-varbind byte-varset)))
+ − 1973 (byte-compile-log-lap " %s %s %s\t-->\t%s dup %s"
+ − 1974 lap0 lap1 lap0 lap0 lap1)
+ − 1975 (setcar (cdr (cdr rest)) (cons (car lap1) (cdr lap1)))
+ − 1976 (setcar (cdr rest) (cons 'byte-dup 0))
+ − 1977 (setq add-depth 1))
+ − 1978 ;;
+ − 1979 ;; const-X [dup/const-X ...] --> const-X [dup ...] dup
+ − 1980 ;; varref-X [dup/varref-X ...] --> varref-X [dup ...] dup
+ − 1981 ;;
+ − 1982 ((memq (car lap0) '(byte-constant byte-varref))
+ − 1983 (setq tmp rest
+ − 1984 tmp2 nil)
+ − 1985 (while (progn
+ − 1986 (while (eq 'byte-dup (car (car (setq tmp (cdr tmp))))))
+ − 1987 (and (eq (cdr lap0) (cdr (car tmp)))
+ − 1988 (eq (car lap0) (car (car tmp)))))
+ − 1989 (setcar tmp (cons 'byte-dup 0))
+ − 1990 (setq tmp2 t))
+ − 1991 (if tmp2
+ − 1992 (byte-compile-log-lap
+ − 1993 " %s [dup/%s]...\t-->\t%s dup..." lap0 lap0 lap0)))
+ − 1994 ;;
+ − 1995 ;; unbind-N unbind-M --> unbind-(N+M)
+ − 1996 ;;
+ − 1997 ((and (eq 'byte-unbind (car lap0))
+ − 1998 (eq 'byte-unbind (car lap1)))
+ − 1999 (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1
+ − 2000 (cons 'byte-unbind
+ − 2001 (+ (cdr lap0) (cdr lap1))))
+ − 2002 (setq keep-going t)
+ − 2003 (setq lap (delq lap0 lap))
+ − 2004 (setcdr lap1 (+ (cdr lap1) (cdr lap0))))
+ − 2005 )
+ − 2006 (setq rest (cdr rest)))
442
+ − 2007 ;; Since the first 6 entries of the compiled-function constants
+ − 2008 ;; vector are most efficient for varref/set/bind ops, we sort by
+ − 2009 ;; reference count. This generates maximally space efficient and
+ − 2010 ;; pretty time-efficient byte-code. See `byte-compile-constants-vector'.
+ − 2011 (setq byte-compile-variables
+ − 2012 (sort byte-compile-variables
+ − 2013 #'(lambda (v1 v2)
+ − 2014 (< (gethash v1 variable-frequency)
+ − 2015 (gethash v2 variable-frequency)))))
+ − 2016 ;; Another hack - put the most used variable in position 6, for
+ − 2017 ;; better locality of reference with adjoining constants.
+ − 2018 (let ((tail (last byte-compile-variables 6)))
+ − 2019 (setq byte-compile-variables
+ − 2020 (append (nbutlast byte-compile-variables 6)
+ − 2021 (nreverse tail))))
428
+ − 2022 (setq byte-compile-maxdepth (+ byte-compile-maxdepth add-depth)))
+ − 2023 lap)
+ − 2024
+ − 2025 (provide 'byte-optimize)
+ − 2026
+ − 2027
+ − 2028 ;; To avoid "lisp nesting exceeds max-lisp-eval-depth" when this file compiles
+ − 2029 ;; itself, compile some of its most used recursive functions (at load time).
+ − 2030 ;;
+ − 2031 (eval-when-compile
+ − 2032 (or (compiled-function-p (symbol-function 'byte-optimize-form))
+ − 2033 (assq 'byte-code (symbol-function 'byte-optimize-form))
+ − 2034 (let ((byte-optimize nil)
+ − 2035 (byte-compile-warnings nil))
+ − 2036 (mapcar
+ − 2037 #'(lambda (x)
+ − 2038 (or noninteractive (message "compiling %s..." x))
+ − 2039 (byte-compile x)
+ − 2040 (or noninteractive (message "compiling %s...done" x)))
+ − 2041 '(byte-optimize-form
+ − 2042 byte-optimize-body
+ − 2043 byte-optimize-predicate
+ − 2044 byte-optimize-binary-predicate
+ − 2045 ;; Inserted some more than necessary, to speed it up.
+ − 2046 byte-optimize-form-code-walker
+ − 2047 byte-optimize-lapcode))))
+ − 2048 nil)
+ − 2049
+ − 2050 ;;; byte-optimize.el ends here