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
1297
+ − 27 ;;; Synched up with: FSF 20.7 except where marked.
+ − 28 ;;; [[ Synched up with: FSF 20.7. ]]
+ − 29 ;;; DO NOT PUT IN AN INVALID SYNC MESSAGE WHEN YOU DO A PARTIAL SYNC. --ben
+ − 30
+ − 31 ;; BEGIN SYNC WITH 20.7.
428
+ − 32
+ − 33 ;;; Commentary:
+ − 34
+ − 35 ;; ========================================================================
+ − 36 ;; "No matter how hard you try, you can't make a racehorse out of a pig.
+ − 37 ;; You can, however, make a faster pig."
+ − 38 ;;
+ − 39 ;; Or, to put it another way, the emacs byte compiler is a VW Bug. This code
440
+ − 40 ;; makes it be a VW Bug with fuel injection and a turbocharger... You're
428
+ − 41 ;; still not going to make it go faster than 70 mph, but it might be easier
+ − 42 ;; to get it there.
+ − 43 ;;
+ − 44
+ − 45 ;; TO DO:
+ − 46 ;;
+ − 47 ;; (apply #'(lambda (x &rest y) ...) 1 (foo))
+ − 48 ;;
+ − 49 ;; maintain a list of functions known not to access any global variables
+ − 50 ;; (actually, give them a 'dynamically-safe property) and then
+ − 51 ;; (let ( v1 v2 ... vM vN ) <...dynamically-safe...> ) ==>
+ − 52 ;; (let ( v1 v2 ... vM ) vN <...dynamically-safe...> )
+ − 53 ;; by recursing on this, we might be able to eliminate the entire let.
+ − 54 ;; However certain variables should never have their bindings optimized
+ − 55 ;; away, because they affect everything.
+ − 56 ;; (put 'debug-on-error 'binding-is-magic t)
+ − 57 ;; (put 'debug-on-abort 'binding-is-magic t)
+ − 58 ;; (put 'debug-on-next-call 'binding-is-magic t)
+ − 59 ;; (put 'mocklisp-arguments 'binding-is-magic t)
+ − 60 ;; (put 'inhibit-quit 'binding-is-magic t)
+ − 61 ;; (put 'quit-flag 'binding-is-magic t)
+ − 62 ;; (put 't 'binding-is-magic t)
+ − 63 ;; (put 'nil 'binding-is-magic t)
+ − 64 ;; possibly also
+ − 65 ;; (put 'gc-cons-threshold 'binding-is-magic t)
+ − 66 ;; (put 'track-mouse 'binding-is-magic t)
+ − 67 ;; others?
+ − 68 ;;
+ − 69 ;; Simple defsubsts often produce forms like
+ − 70 ;; (let ((v1 (f1)) (v2 (f2)) ...)
+ − 71 ;; (FN v1 v2 ...))
440
+ − 72 ;; It would be nice if we could optimize this to
428
+ − 73 ;; (FN (f1) (f2) ...)
+ − 74 ;; but we can't unless FN is dynamically-safe (it might be dynamically
+ − 75 ;; referring to the bindings that the lambda arglist established.)
+ − 76 ;; One of the uncountable lossages introduced by dynamic scope...
+ − 77 ;;
440
+ − 78 ;; Maybe there should be a control-structure that says "turn on
428
+ − 79 ;; fast-and-loose type-assumptive optimizations here." Then when
+ − 80 ;; we see a form like (car foo) we can from then on assume that
+ − 81 ;; the variable foo is of type cons, and optimize based on that.
440
+ − 82 ;; But, this won't win much because of (you guessed it) dynamic
428
+ − 83 ;; scope. Anything down the stack could change the value.
+ − 84 ;; (Another reason it doesn't work is that it is perfectly valid
+ − 85 ;; to call car with a null argument.) A better approach might
+ − 86 ;; be to allow type-specification of the form
+ − 87 ;; (put 'foo 'arg-types '(float (list integer) dynamic))
+ − 88 ;; (put 'foo 'result-type 'bool)
+ − 89 ;; It should be possible to have these types checked to a certain
+ − 90 ;; degree.
+ − 91 ;;
+ − 92 ;; collapse common subexpressions
+ − 93 ;;
+ − 94 ;; It would be nice if redundant sequences could be factored out as well,
+ − 95 ;; when they are known to have no side-effects:
+ − 96 ;; (list (+ a b c) (+ a b c)) --> a b add c add dup list-2
+ − 97 ;; but beware of traps like
+ − 98 ;; (cons (list x y) (list x y))
+ − 99 ;;
+ − 100 ;; Tail-recursion elimination is not really possible in Emacs Lisp.
+ − 101 ;; Tail-recursion elimination is almost always impossible when all variables
+ − 102 ;; have dynamic scope, but given that the "return" byteop requires the
+ − 103 ;; binding stack to be empty (rather than emptying it itself), there can be
+ − 104 ;; no truly tail-recursive Emacs Lisp functions that take any arguments or
+ − 105 ;; make any bindings.
+ − 106 ;;
+ − 107 ;; Here is an example of an Emacs Lisp function which could safely be
+ − 108 ;; byte-compiled tail-recursively:
+ − 109 ;;
+ − 110 ;; (defun tail-map (fn list)
+ − 111 ;; (cond (list
+ − 112 ;; (funcall fn (car list))
+ − 113 ;; (tail-map fn (cdr list)))))
+ − 114 ;;
+ − 115 ;; However, if there was even a single let-binding around the COND,
+ − 116 ;; it could not be byte-compiled, because there would be an "unbind"
440
+ − 117 ;; byte-op between the final "call" and "return." Adding a
428
+ − 118 ;; Bunbind_all byteop would fix this.
+ − 119 ;;
+ − 120 ;; (defun foo (x y z) ... (foo a b c))
+ − 121 ;; ... (const foo) (varref a) (varref b) (varref c) (call 3) END: (return)
+ − 122 ;; ... (varref a) (varbind x) (varref b) (varbind y) (varref c) (varbind z) (goto 0) END: (unbind-all) (return)
+ − 123 ;; ... (varref a) (varset x) (varref b) (varset y) (varref c) (varset z) (goto 0) END: (return)
+ − 124 ;;
+ − 125 ;; this also can be considered tail recursion:
+ − 126 ;;
+ − 127 ;; ... (const foo) (varref a) (call 1) (goto X) ... X: (return)
+ − 128 ;; could generalize this by doing the optimization
+ − 129 ;; (goto X) ... X: (return) --> (return)
+ − 130 ;;
+ − 131 ;; But this doesn't solve all of the problems: although by doing tail-
+ − 132 ;; recursion elimination in this way, the call-stack does not grow, the
+ − 133 ;; binding-stack would grow with each recursive step, and would eventually
+ − 134 ;; overflow. I don't believe there is any way around this without lexical
+ − 135 ;; scope.
+ − 136 ;;
+ − 137 ;; Wouldn't it be nice if Emacs Lisp had lexical scope.
+ − 138 ;;
440
+ − 139 ;; Idea: the form (lexical-scope) in a file means that the file may be
+ − 140 ;; compiled lexically. This proclamation is file-local. Then, within
428
+ − 141 ;; that file, "let" would establish lexical bindings, and "let-dynamic"
+ − 142 ;; would do things the old way. (Or we could use CL "declare" forms.)
+ − 143 ;; We'd have to notice defvars and defconsts, since those variables should
+ − 144 ;; always be dynamic, and attempting to do a lexical binding of them
+ − 145 ;; should simply do a dynamic binding instead.
+ − 146 ;; But! We need to know about variables that were not necessarily defvarred
+ − 147 ;; in the file being compiled (doing a boundp check isn't good enough.)
+ − 148 ;; Fdefvar() would have to be modified to add something to the plist.
+ − 149 ;;
440
+ − 150 ;; A major disadvantage of this scheme is that the interpreter and compiler
+ − 151 ;; would have different semantics for files compiled with (dynamic-scope).
428
+ − 152 ;; Since this would be a file-local optimization, there would be no way to
440
+ − 153 ;; modify the interpreter to obey this (unless the loader was hacked
428
+ − 154 ;; in some grody way, but that's a really bad idea.)
+ − 155 ;;
+ − 156 ;; HA! RMS removed the following paragraph from his version of
+ − 157 ;; byte-optimize.el.
+ − 158 ;;
+ − 159 ;; Really the Right Thing is to make lexical scope the default across
440
+ − 160 ;; the board, in the interpreter and compiler, and just FIX all of
428
+ − 161 ;; the code that relies on dynamic scope of non-defvarred variables.
+ − 162
+ − 163 ;; Other things to consider:
+ − 164
+ − 165 ;; Associative math should recognize subcalls to identical function:
+ − 166 ;;(disassemble #'(lambda (x) (+ (+ (foo) 1) (+ (bar) 2))))
+ − 167 ;; This should generate the same as (1+ x) and (1- x)
+ − 168
+ − 169 ;;(disassemble #'(lambda (x) (cons (+ x 1) (- x 1))))
+ − 170 ;; An awful lot of functions always return a non-nil value. If they're
+ − 171 ;; error free also they may act as true-constants.
+ − 172
+ − 173 ;;(disassemble #'(lambda (x) (and (point) (foo))))
440
+ − 174 ;; When
428
+ − 175 ;; - all but one arguments to a function are constant
+ − 176 ;; - the non-constant argument is an if-expression (cond-expression?)
+ − 177 ;; then the outer function can be distributed. If the guarding
+ − 178 ;; condition is side-effect-free [assignment-free] then the other
+ − 179 ;; arguments may be any expressions. Since, however, the code size
+ − 180 ;; can increase this way they should be "simple". Compare:
+ − 181
+ − 182 ;;(disassemble #'(lambda (x) (eq (if (point) 'a 'b) 'c)))
+ − 183 ;;(disassemble #'(lambda (x) (if (point) (eq 'a 'c) (eq 'b 'c))))
+ − 184
444
+ − 185 ;; (car (cons A B)) -> (prog1 A B)
428
+ − 186 ;;(disassemble #'(lambda (x) (car (cons (foo) 42))))
+ − 187
+ − 188 ;; (cdr (cons A B)) -> (progn A B)
+ − 189 ;;(disassemble #'(lambda (x) (cdr (cons 42 (foo)))))
+ − 190
444
+ − 191 ;; (car (list A B ...)) -> (prog1 A ... B)
428
+ − 192 ;;(disassemble #'(lambda (x) (car (list (foo) 42 (bar)))))
+ − 193
+ − 194 ;; (cdr (list A B ...)) -> (progn A (list B ...))
+ − 195 ;;(disassemble #'(lambda (x) (cdr (list 42 (foo) (bar)))))
+ − 196
+ − 197
+ − 198 ;;; Code:
+ − 199
+ − 200 (require 'byte-compile "bytecomp")
+ − 201
+ − 202 (defun byte-compile-log-lap-1 (format &rest args)
+ − 203 (if (aref byte-code-vector 0)
+ − 204 (error "The old version of the disassembler is loaded. Reload new-bytecomp as well."))
+ − 205 (byte-compile-log-1
+ − 206 (apply 'format format
+ − 207 (let (c a)
+ − 208 (mapcar
+ − 209 #'(lambda (arg)
+ − 210 (if (not (consp arg))
+ − 211 (if (and (symbolp arg)
+ − 212 (string-match "^byte-" (symbol-name arg)))
+ − 213 (intern (substring (symbol-name arg) 5))
+ − 214 arg)
+ − 215 (if (integerp (setq c (car arg)))
+ − 216 (error "non-symbolic byte-op %s" c))
+ − 217 (if (eq c 'TAG)
+ − 218 (setq c arg)
+ − 219 (setq a (cond ((memq c byte-goto-ops)
+ − 220 (car (cdr (cdr arg))))
+ − 221 ((memq c byte-constref-ops)
+ − 222 (car (cdr arg)))
+ − 223 (t (cdr arg))))
+ − 224 (setq c (symbol-name c))
+ − 225 (if (string-match "^byte-." c)
+ − 226 (setq c (intern (substring c 5)))))
+ − 227 (if (eq c 'constant) (setq c 'const))
+ − 228 (if (and (eq (cdr arg) 0)
+ − 229 (not (memq c '(unbind call const))))
+ − 230 c
+ − 231 (format "(%s %s)" c a))))
+ − 232 args)))))
+ − 233
+ − 234 (defmacro byte-compile-log-lap (format-string &rest args)
+ − 235 (list 'and
+ − 236 '(memq byte-optimize-log '(t byte))
+ − 237 (cons 'byte-compile-log-lap-1
+ − 238 (cons format-string args))))
+ − 239
+ − 240
+ − 241 ;;; byte-compile optimizers to support inlining
+ − 242
+ − 243 (put 'inline 'byte-optimizer 'byte-optimize-inline-handler)
+ − 244
+ − 245 (defun byte-optimize-inline-handler (form)
+ − 246 "byte-optimize-handler for the `inline' special-form."
+ − 247 (cons
+ − 248 'progn
+ − 249 (mapcar
+ − 250 #'(lambda (sexp)
+ − 251 (let ((fn (car-safe sexp)))
+ − 252 (if (and (symbolp fn)
+ − 253 (or (cdr (assq fn byte-compile-function-environment))
+ − 254 (and (fboundp fn)
+ − 255 (not (or (cdr (assq fn byte-compile-macro-environment))
+ − 256 (and (consp (setq fn (symbol-function fn)))
+ − 257 (eq (car fn) 'macro))
+ − 258 (subrp fn))))))
+ − 259 (byte-compile-inline-expand sexp)
+ − 260 sexp)))
+ − 261 (cdr form))))
+ − 262
+ − 263
+ − 264 ;; Splice the given lap code into the current instruction stream.
+ − 265 ;; If it has any labels in it, you're responsible for making sure there
+ − 266 ;; are no collisions, and that byte-compile-tag-number is reasonable
+ − 267 ;; after this is spliced in. The provided list is destroyed.
+ − 268 (defun byte-inline-lapcode (lap)
+ − 269 (setq byte-compile-output (nconc (nreverse lap) byte-compile-output)))
+ − 270
+ − 271
+ − 272 (defun byte-compile-inline-expand (form)
+ − 273 (let* ((name (car form))
+ − 274 (fn (or (cdr (assq name byte-compile-function-environment))
+ − 275 (and (fboundp name) (symbol-function name)))))
+ − 276 (if (null fn)
+ − 277 (progn
+ − 278 (byte-compile-warn "attempt to inline %s before it was defined" name)
+ − 279 form)
+ − 280 ;; else
+ − 281 (if (and (consp fn) (eq (car fn) 'autoload))
+ − 282 (progn
+ − 283 (load (nth 1 fn))
+ − 284 (setq fn (or (cdr (assq name byte-compile-function-environment))
+ − 285 (and (fboundp name) (symbol-function name))))))
+ − 286 (if (and (consp fn) (eq (car fn) 'autoload))
+ − 287 (error "file \"%s\" didn't define \"%s\"" (nth 1 fn) name))
+ − 288 (if (symbolp fn)
+ − 289 (byte-compile-inline-expand (cons fn (cdr form)))
+ − 290 (if (compiled-function-p fn)
+ − 291 (progn
+ − 292 (fetch-bytecode fn)
+ − 293 (cons (list 'lambda (compiled-function-arglist fn)
+ − 294 (list 'byte-code
+ − 295 (compiled-function-instructions fn)
+ − 296 (compiled-function-constants fn)
+ − 297 (compiled-function-stack-depth fn)))
+ − 298 (cdr form)))
1297
+ − 299 (if (eq (car-safe fn) 'lambda)
+ − 300 (cons fn (cdr form))
+ − 301 ;; Give up on inlining.
+ − 302 form))))))
428
+ − 303
+ − 304 ;;; ((lambda ...) ...)
440
+ − 305 ;;;
428
+ − 306 (defun byte-compile-unfold-lambda (form &optional name)
+ − 307 (or name (setq name "anonymous lambda"))
+ − 308 (let ((lambda (car form))
+ − 309 (values (cdr form)))
+ − 310 (if (compiled-function-p lambda)
+ − 311 (setq lambda (list 'lambda (compiled-function-arglist lambda)
+ − 312 (list 'byte-code
+ − 313 (compiled-function-instructions lambda)
+ − 314 (compiled-function-constants lambda)
+ − 315 (compiled-function-stack-depth lambda)))))
+ − 316 (let ((arglist (nth 1 lambda))
+ − 317 (body (cdr (cdr lambda)))
+ − 318 optionalp restp
+ − 319 bindings)
+ − 320 (if (and (stringp (car body)) (cdr body))
+ − 321 (setq body (cdr body)))
+ − 322 (if (and (consp (car body)) (eq 'interactive (car (car body))))
+ − 323 (setq body (cdr body)))
+ − 324 (while arglist
+ − 325 (cond ((eq (car arglist) '&optional)
+ − 326 ;; ok, I'll let this slide because funcall_lambda() does...
+ − 327 ;; (if optionalp (error "multiple &optional keywords in %s" name))
+ − 328 (if restp (error "&optional found after &rest in %s" name))
+ − 329 (if (null (cdr arglist))
+ − 330 (error "nothing after &optional in %s" name))
+ − 331 (setq optionalp t))
+ − 332 ((eq (car arglist) '&rest)
+ − 333 ;; ...but it is by no stretch of the imagination a reasonable
+ − 334 ;; thing that funcall_lambda() allows (&rest x y) and
+ − 335 ;; (&rest x &optional y) in arglists.
+ − 336 (if (null (cdr arglist))
+ − 337 (error "nothing after &rest in %s" name))
+ − 338 (if (cdr (cdr arglist))
+ − 339 (error "multiple vars after &rest in %s" name))
+ − 340 (setq restp t))
+ − 341 (restp
+ − 342 (setq bindings (cons (list (car arglist)
+ − 343 (and values (cons 'list values)))
+ − 344 bindings)
+ − 345 values nil))
+ − 346 ((and (not optionalp) (null values))
+ − 347 (byte-compile-warn "attempt to open-code %s with too few arguments" name)
+ − 348 (setq arglist nil values 'too-few))
+ − 349 (t
+ − 350 (setq bindings (cons (list (car arglist) (car values))
+ − 351 bindings)
+ − 352 values (cdr values))))
+ − 353 (setq arglist (cdr arglist)))
+ − 354 (if values
+ − 355 (progn
+ − 356 (or (eq values 'too-few)
+ − 357 (byte-compile-warn
+ − 358 "attempt to open-code %s with too many arguments" name))
+ − 359 form)
1297
+ − 360 (setq body (mapcar 'byte-optimize-form body))
440
+ − 361 (let ((newform
428
+ − 362 (if bindings
+ − 363 (cons 'let (cons (nreverse bindings) body))
+ − 364 (cons 'progn body))))
+ − 365 (byte-compile-log " %s\t==>\t%s" form newform)
+ − 366 newform)))))
+ − 367
+ − 368
+ − 369 ;;; implementing source-level optimizers
+ − 370
+ − 371 (defun byte-optimize-form-code-walker (form for-effect)
+ − 372 ;;
+ − 373 ;; For normal function calls, We can just mapcar the optimizer the cdr. But
+ − 374 ;; we need to have special knowledge of the syntax of the special forms
+ − 375 ;; like let and defun (that's why they're special forms :-). (Actually,
+ − 376 ;; the important aspect is that they are subrs that don't evaluate all of
+ − 377 ;; their args.)
+ − 378 ;;
+ − 379 (let ((fn (car-safe form))
+ − 380 tmp)
+ − 381 (cond ((not (consp form))
+ − 382 (if (not (and for-effect
+ − 383 (or byte-compile-delete-errors
+ − 384 (not (symbolp form))
+ − 385 (eq form t))))
+ − 386 form))
+ − 387 ((eq fn 'quote)
+ − 388 (if (cdr (cdr form))
+ − 389 (byte-compile-warn "malformed quote form: %s"
+ − 390 (prin1-to-string form)))
+ − 391 ;; map (quote nil) to nil to simplify optimizer logic.
+ − 392 ;; map quoted constants to nil if for-effect (just because).
+ − 393 (and (nth 1 form)
+ − 394 (not for-effect)
+ − 395 form))
+ − 396 ((or (compiled-function-p fn)
+ − 397 (eq 'lambda (car-safe fn)))
+ − 398 (byte-compile-unfold-lambda form))
+ − 399 ((memq fn '(let let*))
+ − 400 ;; recursively enter the optimizer for the bindings and body
+ − 401 ;; of a let or let*. This for depth-firstness: forms that
+ − 402 ;; are more deeply nested are optimized first.
+ − 403 (cons fn
+ − 404 (cons
+ − 405 (mapcar
+ − 406 #'(lambda (binding)
+ − 407 (if (symbolp binding)
+ − 408 binding
+ − 409 (if (cdr (cdr binding))
+ − 410 (byte-compile-warn "malformed let binding: %s"
+ − 411 (prin1-to-string binding)))
+ − 412 (list (car binding)
+ − 413 (byte-optimize-form (nth 1 binding) nil))))
+ − 414 (nth 1 form))
+ − 415 (byte-optimize-body (cdr (cdr form)) for-effect))))
+ − 416 ((eq fn 'cond)
+ − 417 (cons fn
+ − 418 (mapcar
+ − 419 #'(lambda (clause)
+ − 420 (if (consp clause)
+ − 421 (cons
+ − 422 (byte-optimize-form (car clause) nil)
+ − 423 (byte-optimize-body (cdr clause) for-effect))
+ − 424 (byte-compile-warn "malformed cond form: %s"
+ − 425 (prin1-to-string clause))
+ − 426 clause))
+ − 427 (cdr form))))
+ − 428 ((eq fn 'progn)
+ − 429 ;; as an extra added bonus, this simplifies (progn <x>) --> <x>
+ − 430 (if (cdr (cdr form))
+ − 431 (progn
+ − 432 (setq tmp (byte-optimize-body (cdr form) for-effect))
+ − 433 (if (cdr tmp) (cons 'progn tmp) (car tmp)))
+ − 434 (byte-optimize-form (nth 1 form) for-effect)))
+ − 435 ((eq fn 'prog1)
+ − 436 (if (cdr (cdr form))
+ − 437 (cons 'prog1
+ − 438 (cons (byte-optimize-form (nth 1 form) for-effect)
+ − 439 (byte-optimize-body (cdr (cdr form)) t)))
+ − 440 (byte-optimize-form (nth 1 form) for-effect)))
+ − 441 ((eq fn 'prog2)
+ − 442 (cons 'prog2
+ − 443 (cons (byte-optimize-form (nth 1 form) t)
+ − 444 (cons (byte-optimize-form (nth 2 form) for-effect)
+ − 445 (byte-optimize-body (cdr (cdr (cdr form))) t)))))
440
+ − 446
428
+ − 447 ((memq fn '(save-excursion save-restriction save-current-buffer))
+ − 448 ;; those subrs which have an implicit progn; it's not quite good
+ − 449 ;; enough to treat these like normal function calls.
+ − 450 ;; This can turn (save-excursion ...) into (save-excursion) which
+ − 451 ;; will be optimized away in the lap-optimize pass.
+ − 452 (cons fn (byte-optimize-body (cdr form) for-effect)))
440
+ − 453
428
+ − 454 ((eq fn 'with-output-to-temp-buffer)
+ − 455 ;; this is just like the above, except for the first argument.
+ − 456 (cons fn
+ − 457 (cons
+ − 458 (byte-optimize-form (nth 1 form) nil)
+ − 459 (byte-optimize-body (cdr (cdr form)) for-effect))))
440
+ − 460
428
+ − 461 ((eq fn 'if)
+ − 462 (cons fn
+ − 463 (cons (byte-optimize-form (nth 1 form) nil)
+ − 464 (cons
+ − 465 (byte-optimize-form (nth 2 form) for-effect)
+ − 466 (byte-optimize-body (nthcdr 3 form) for-effect)))))
440
+ − 467
428
+ − 468 ((memq fn '(and or)) ; remember, and/or are control structures.
+ − 469 ;; take forms off the back until we can't any more.
+ − 470 ;; In the future it could conceivably be a problem that the
+ − 471 ;; subexpressions of these forms are optimized in the reverse
+ − 472 ;; order, but it's ok for now.
+ − 473 (if for-effect
+ − 474 (let ((backwards (reverse (cdr form))))
+ − 475 (while (and backwards
+ − 476 (null (setcar backwards
+ − 477 (byte-optimize-form (car backwards)
+ − 478 for-effect))))
+ − 479 (setq backwards (cdr backwards)))
+ − 480 (if (and (cdr form) (null backwards))
+ − 481 (byte-compile-log
+ − 482 " all subforms of %s called for effect; deleted" form))
452
+ − 483 (when backwards
+ − 484 ;; Now optimize the rest of the forms. We need the return
+ − 485 ;; values. We already did the car.
+ − 486 (setcdr backwards
+ − 487 (mapcar 'byte-optimize-form (cdr backwards))))
+ − 488 (cons fn (nreverse backwards)))
428
+ − 489 (cons fn (mapcar 'byte-optimize-form (cdr form)))))
+ − 490
+ − 491 ((eq fn 'interactive)
+ − 492 (byte-compile-warn "misplaced interactive spec: %s"
+ − 493 (prin1-to-string form))
+ − 494 nil)
440
+ − 495
428
+ − 496 ((memq fn '(defun defmacro function
+ − 497 condition-case save-window-excursion))
+ − 498 ;; These forms are compiled as constants or by breaking out
+ − 499 ;; all the subexpressions and compiling them separately.
+ − 500 form)
+ − 501
+ − 502 ((eq fn 'unwind-protect)
+ − 503 ;; the "protected" part of an unwind-protect is compiled (and thus
+ − 504 ;; optimized) as a top-level form, so don't do it here. But the
+ − 505 ;; non-protected part has the same for-effect status as the
+ − 506 ;; unwind-protect itself. (The protected part is always for effect,
+ − 507 ;; but that isn't handled properly yet.)
+ − 508 (cons fn
+ − 509 (cons (byte-optimize-form (nth 1 form) for-effect)
+ − 510 (cdr (cdr form)))))
440
+ − 511
428
+ − 512 ((eq fn 'catch)
+ − 513 ;; the body of a catch is compiled (and thus optimized) as a
+ − 514 ;; top-level form, so don't do it here. The tag is never
+ − 515 ;; for-effect. The body should have the same for-effect status
+ − 516 ;; as the catch form itself, but that isn't handled properly yet.
+ − 517 (cons fn
+ − 518 (cons (byte-optimize-form (nth 1 form) nil)
+ − 519 (cdr (cdr form)))))
+ − 520
+ − 521 ;; If optimization is on, this is the only place that macros are
+ − 522 ;; expanded. If optimization is off, then macroexpansion happens
+ − 523 ;; in byte-compile-form. Otherwise, the macros are already expanded
+ − 524 ;; by the time that is reached.
+ − 525 ((not (eq form
+ − 526 (setq form (macroexpand form
+ − 527 byte-compile-macro-environment))))
+ − 528 (byte-optimize-form form for-effect))
440
+ − 529
1297
+ − 530 ;; Support compiler macros as in cl.el.
+ − 531 ((and (fboundp 'compiler-macroexpand)
+ − 532 (symbolp (car-safe form))
+ − 533 (get (car-safe form) 'cl-compiler-macro)
+ − 534 (not (eq form
+ − 535 (setq form (compiler-macroexpand form)))))
+ − 536 (byte-optimize-form form for-effect))
+ − 537
428
+ − 538 ((not (symbolp fn))
+ − 539 (or (eq 'mocklisp (car-safe fn)) ; ha!
+ − 540 (byte-compile-warn "%s is a malformed function"
+ − 541 (prin1-to-string fn)))
+ − 542 form)
+ − 543
+ − 544 ((and for-effect (setq tmp (get fn 'side-effect-free))
+ − 545 (or byte-compile-delete-errors
+ − 546 (eq tmp 'error-free)
+ − 547 (progn
+ − 548 (byte-compile-warn "%s called for effect"
+ − 549 (prin1-to-string form))
+ − 550 nil)))
+ − 551 (byte-compile-log " %s called for effect; deleted" fn)
+ − 552 ;; appending a nil here might not be necessary, but it can't hurt.
+ − 553 (byte-optimize-form
+ − 554 (cons 'progn (append (cdr form) '(nil))) t))
440
+ − 555
428
+ − 556 (t
+ − 557 ;; Otherwise, no args can be considered to be for-effect,
+ − 558 ;; even if the called function is for-effect, because we
+ − 559 ;; don't know anything about that function.
+ − 560 (cons fn (mapcar 'byte-optimize-form (cdr form)))))))
+ − 561
+ − 562
+ − 563 (defun byte-optimize-form (form &optional for-effect)
+ − 564 "The source-level pass of the optimizer."
+ − 565 ;;
+ − 566 ;; First, optimize all sub-forms of this one.
+ − 567 (setq form (byte-optimize-form-code-walker form for-effect))
+ − 568 ;;
+ − 569 ;; After optimizing all subforms, optimize this form until it doesn't
+ − 570 ;; optimize any further. This means that some forms will be passed through
+ − 571 ;; the optimizer many times, but that's necessary to make the for-effect
+ − 572 ;; processing do as much as possible.
+ − 573 ;;
+ − 574 (let (opt new)
+ − 575 (if (and (consp form)
+ − 576 (symbolp (car form))
+ − 577 (or (and for-effect
+ − 578 ;; we don't have any of these yet, but we might.
+ − 579 (setq opt (get (car form) 'byte-for-effect-optimizer)))
+ − 580 (setq opt (get (car form) 'byte-optimizer)))
+ − 581 (not (eq form (setq new (funcall opt form)))))
+ − 582 (progn
+ − 583 ;; (if (equal form new) (error "bogus optimizer -- %s" opt))
+ − 584 (byte-compile-log " %s\t==>\t%s" form new)
1297
+ − 585 (setq new (byte-optimize-form new for-effect))
+ − 586 new)
428
+ − 587 form)))
+ − 588
+ − 589
+ − 590 (defun byte-optimize-body (forms all-for-effect)
+ − 591 ;; Optimize the cdr of a progn or implicit progn; `forms' is a list of
+ − 592 ;; forms, all but the last of which are optimized with the assumption that
+ − 593 ;; they are being called for effect. The last is for-effect as well if
+ − 594 ;; all-for-effect is true. Returns a new list of forms.
+ − 595 (let ((rest forms)
+ − 596 (result nil)
+ − 597 fe new)
+ − 598 (while rest
+ − 599 (setq fe (or all-for-effect (cdr rest)))
+ − 600 (setq new (and (car rest) (byte-optimize-form (car rest) fe)))
+ − 601 (if (or new (not fe))
+ − 602 (setq result (cons new result)))
+ − 603 (setq rest (cdr rest)))
+ − 604 (nreverse result)))
+ − 605
+ − 606
+ − 607 ;;; some source-level optimizers
+ − 608 ;;;
+ − 609 ;;; when writing optimizers, be VERY careful that the optimizer returns
+ − 610 ;;; something not EQ to its argument if and ONLY if it has made a change.
+ − 611 ;;; This implies that you cannot simply destructively modify the list;
+ − 612 ;;; you must return something not EQ to it if you make an optimization.
+ − 613 ;;;
+ − 614 ;;; It is now safe to optimize code such that it introduces new bindings.
+ − 615
+ − 616 ;; I'd like this to be a defsubst, but let's not be self-referential...
+ − 617 (defmacro byte-compile-trueconstp (form)
+ − 618 ;; Returns non-nil if FORM is a non-nil constant.
+ − 619 `(cond ((consp ,form) (eq (car ,form) 'quote))
+ − 620 ((not (symbolp ,form)))
+ − 621 ((eq ,form t))
+ − 622 ((keywordp ,form))))
+ − 623
+ − 624 ;; If the function is being called with constant numeric args,
440
+ − 625 ;; evaluate as much as possible at compile-time. This optimizer
428
+ − 626 ;; assumes that the function is associative, like + or *.
+ − 627 (defun byte-optimize-associative-math (form)
+ − 628 (let ((args nil)
+ − 629 (constants nil)
+ − 630 (rest (cdr form)))
+ − 631 (while rest
+ − 632 (if (numberp (car rest))
+ − 633 (setq constants (cons (car rest) constants))
+ − 634 (setq args (cons (car rest) args)))
+ − 635 (setq rest (cdr rest)))
+ − 636 (if (cdr constants)
+ − 637 (if args
+ − 638 (list (car form)
+ − 639 (apply (car form) constants)
+ − 640 (if (cdr args)
+ − 641 (cons (car form) (nreverse args))
+ − 642 (car args)))
+ − 643 (apply (car form) constants))
+ − 644 form)))
+ − 645
+ − 646 ;; If the function is being called with constant numeric args,
+ − 647 ;; evaluate as much as possible at compile-time. This optimizer
+ − 648 ;; assumes that the function satisfies
+ − 649 ;; (op x1 x2 ... xn) == (op ...(op (op x1 x2) x3) ...xn)
+ − 650 ;; like - and /.
+ − 651 (defun byte-optimize-nonassociative-math (form)
+ − 652 (if (or (not (numberp (car (cdr form))))
+ − 653 (not (numberp (car (cdr (cdr form))))))
+ − 654 form
+ − 655 (let ((constant (car (cdr form)))
+ − 656 (rest (cdr (cdr form))))
+ − 657 (while (numberp (car rest))
+ − 658 (setq constant (funcall (car form) constant (car rest))
+ − 659 rest (cdr rest)))
+ − 660 (if rest
+ − 661 (cons (car form) (cons constant rest))
+ − 662 constant))))
+ − 663
+ − 664 ;;(defun byte-optimize-associative-two-args-math (form)
+ − 665 ;; (setq form (byte-optimize-associative-math form))
+ − 666 ;; (if (consp form)
+ − 667 ;; (byte-optimize-two-args-left form)
+ − 668 ;; form))
+ − 669
+ − 670 ;;(defun byte-optimize-nonassociative-two-args-math (form)
+ − 671 ;; (setq form (byte-optimize-nonassociative-math form))
+ − 672 ;; (if (consp form)
+ − 673 ;; (byte-optimize-two-args-right form)
+ − 674 ;; form))
+ − 675
+ − 676 ;; jwz: (byte-optimize-approx-equal 0.0 0.0) was returning nil
+ − 677 ;; in xemacs 19.15 because it used < instead of <=.
+ − 678 (defun byte-optimize-approx-equal (x y)
+ − 679 (<= (* (abs (- x y)) 100) (abs (+ x y))))
+ − 680
+ − 681 ;; Collect all the constants from FORM, after the STARTth arg,
+ − 682 ;; and apply FUN to them to make one argument at the end.
+ − 683 ;; For functions that can handle floats, that optimization
+ − 684 ;; can be incorrect because reordering can cause an overflow
+ − 685 ;; that would otherwise be avoided by encountering an arg that is a float.
+ − 686 ;; We avoid this problem by (1) not moving float constants and
+ − 687 ;; (2) not moving anything if it would cause an overflow.
+ − 688 (defun byte-optimize-delay-constants-math (form start fun)
+ − 689 ;; Merge all FORM's constants from number START, call FUN on them
+ − 690 ;; and put the result at the end.
+ − 691 (let ((rest (nthcdr (1- start) form))
+ − 692 (orig form)
+ − 693 ;; t means we must check for overflow.
+ − 694 (overflow (memq fun '(+ *))))
+ − 695 (while (cdr (setq rest (cdr rest)))
+ − 696 (if (integerp (car rest))
+ − 697 (let (constants)
+ − 698 (setq form (copy-sequence form)
+ − 699 rest (nthcdr (1- start) form))
+ − 700 (while (setq rest (cdr rest))
+ − 701 (cond ((integerp (car rest))
+ − 702 (setq constants (cons (car rest) constants))
+ − 703 (setcar rest nil))))
+ − 704 ;; If necessary, check now for overflow
+ − 705 ;; that might be caused by reordering.
+ − 706 (if (and overflow
+ − 707 ;; We have overflow if the result of doing the arithmetic
+ − 708 ;; on floats is not even close to the result
+ − 709 ;; of doing it on integers.
+ − 710 (not (byte-optimize-approx-equal
+ − 711 (apply fun (mapcar 'float constants))
+ − 712 (float (apply fun constants)))))
+ − 713 (setq form orig)
+ − 714 (setq form (nconc (delq nil form)
+ − 715 (list (apply fun (nreverse constants)))))))))
+ − 716 form))
+ − 717
1297
+ − 718 ;; END SYNC WITH 20.7.
+ − 719
446
+ − 720 ;;; It is not safe to optimize calls to arithmetic ops with one arg
+ − 721 ;;; away entirely (actually, it would be safe if we know the sole arg
+ − 722 ;;; is not a marker or if it appears in other arithmetic).
428
+ − 723
446
+ − 724 ;;; But this degree of paranoia is normally unjustified, so optimize unless
547
+ − 725 ;;; the user has done (declaim (optimize (safety 3))). See bytecomp.el.
442
+ − 726
446
+ − 727 (defun byte-optimize-plus (form)
+ − 728 (byte-optimize-predicate (byte-optimize-delay-constants-math form 1 '+)))
428
+ − 729
+ − 730 (defun byte-optimize-multiply (form)
+ − 731 (setq form (byte-optimize-delay-constants-math form 1 '*))
442
+ − 732 ;; If there is a constant integer in FORM, it is now the last element.
446
+ − 733
+ − 734 (case (car (last form))
+ − 735 ;; (* x y 0) --> (progn x y 0)
+ − 736 (0 (cons 'progn (cdr form)))
+ − 737 (t (byte-optimize-predicate form))))
+ − 738
+ − 739 (defun byte-optimize-minus (form)
+ − 740 ;; Put constants at the end, except the first arg.
+ − 741 (setq form (byte-optimize-delay-constants-math form 2 '+))
+ − 742 ;; Now only the first and last args can be integers.
+ − 743 (let ((last (car (last (nthcdr 3 form)))))
+ − 744 (cond
+ − 745 ;; If form is (- CONST foo... CONST), merge first and last.
+ − 746 ((and (numberp (nth 1 form)) (numberp last))
+ − 747 (decf (nth 1 form) last)
+ − 748 (butlast form))
+ − 749
464
+ − 750 ;; (- 0 ...) -->
+ − 751 ((eq 0 (nth 1 form))
+ − 752 (case (length form)
+ − 753 ;; (- 0) --> 0
+ − 754 (2 0)
+ − 755 ;; (- 0 x) --> (- x)
+ − 756 (3 `(- ,(nth 2 form)))
+ − 757 ;; (- 0 x y ...) --> (- (- x) y ...)
+ − 758 (t `(- (- ,(nth 2 form)) ,@(nthcdr 3 form)))))
446
+ − 759
+ − 760 (t (byte-optimize-predicate form)))))
428
+ − 761
+ − 762 (defun byte-optimize-divide (form)
446
+ − 763 ;; Put constants at the end, except the first arg.
428
+ − 764 (setq form (byte-optimize-delay-constants-math form 2 '*))
446
+ − 765 ;; Now only the first and last args can be integers.
+ − 766 (let ((last (car (last (nthcdr 3 form)))))
440
+ − 767 (cond
446
+ − 768 ;; If form is (/ CONST foo... CONST), merge first and last.
+ − 769 ((and (numberp (nth 1 form)) (numberp last))
+ − 770 (condition-case nil
+ − 771 (cons (nth 0 form)
+ − 772 (cons (/ (nth 1 form) last)
+ − 773 (butlast (cdr (cdr form)))))
+ − 774 (error form)))
+ − 775
+ − 776 ;; (/ 0 x y) --> (progn x y 0)
442
+ − 777 ((eq (nth 1 form) 0)
+ − 778 (append '(progn) (cdr (cdr form)) '(0)))
446
+ − 779
+ − 780 ;; We don't have to check for divide-by-zero because `/' does.
+ − 781 (t (byte-optimize-predicate form)))))
428
+ − 782
1297
+ − 783 ;; BEGIN SYNC WITH 20.7.
+ − 784
428
+ − 785 (defun byte-optimize-logmumble (form)
+ − 786 (setq form (byte-optimize-delay-constants-math form 1 (car form)))
+ − 787 (byte-optimize-predicate
+ − 788 (cond ((memq 0 form)
+ − 789 (setq form (if (eq (car form) 'logand)
+ − 790 (cons 'progn (cdr form))
+ − 791 (delq 0 (copy-sequence form)))))
+ − 792 ((and (eq (car-safe form) 'logior)
+ − 793 (memq -1 form))
+ − 794 (cons 'progn (cdr form)))
+ − 795 (form))))
+ − 796
+ − 797
+ − 798 (defun byte-optimize-binary-predicate (form)
+ − 799 (if (byte-compile-constp (nth 1 form))
+ − 800 (if (byte-compile-constp (nth 2 form))
+ − 801 (condition-case ()
+ − 802 (list 'quote (eval form))
+ − 803 (error form))
+ − 804 ;; This can enable some lapcode optimizations.
+ − 805 (list (car form) (nth 2 form) (nth 1 form)))
+ − 806 form))
+ − 807
+ − 808 (defun byte-optimize-predicate (form)
+ − 809 (let ((ok t)
+ − 810 (rest (cdr form)))
+ − 811 (while (and rest ok)
+ − 812 (setq ok (byte-compile-constp (car rest))
+ − 813 rest (cdr rest)))
+ − 814 (if ok
446
+ − 815 (condition-case err
428
+ − 816 (list 'quote (eval form))
446
+ − 817 (error
+ − 818 (byte-compile-warn "evaluating %s: %s" form err)
+ − 819 form))
428
+ − 820 form)))
+ − 821
+ − 822 (defun byte-optimize-identity (form)
+ − 823 (if (and (cdr form) (null (cdr (cdr form))))
+ − 824 (nth 1 form)
+ − 825 (byte-compile-warn "identity called with %d arg%s, but requires 1"
+ − 826 (length (cdr form))
+ − 827 (if (= 1 (length (cdr form))) "" "s"))
+ − 828 form))
+ − 829
444
+ − 830 (defun byte-optimize-car (form)
+ − 831 (let ((arg (cadr form)))
+ − 832 (cond
+ − 833 ((and (byte-compile-trueconstp arg)
+ − 834 (not (and (consp arg)
+ − 835 (eq (car arg) 'quote)
+ − 836 (listp (cadr arg)))))
+ − 837 (byte-compile-warn
+ − 838 "taking car of a constant: %s" arg)
+ − 839 form)
+ − 840 ((and (eq (car-safe arg) 'cons)
+ − 841 (eq (length arg) 3))
+ − 842 `(prog1 ,(nth 1 arg) ,(nth 2 arg)))
+ − 843 ((eq (car-safe arg) 'list)
+ − 844 `(prog1 ,@(cdr arg)))
+ − 845 (t
+ − 846 (byte-optimize-predicate form)))))
+ − 847
+ − 848 (defun byte-optimize-cdr (form)
+ − 849 (let ((arg (cadr form)))
+ − 850 (cond
+ − 851 ((and (byte-compile-trueconstp arg)
+ − 852 (not (and (consp arg)
+ − 853 (eq (car arg) 'quote)
+ − 854 (listp (cadr arg)))))
+ − 855 (byte-compile-warn
+ − 856 "taking cdr of a constant: %s" arg)
+ − 857 form)
+ − 858 ((and (eq (car-safe arg) 'cons)
+ − 859 (eq (length arg) 3))
+ − 860 `(progn ,(nth 1 arg) ,(nth 2 arg)))
+ − 861 ((eq (car-safe arg) 'list)
+ − 862 (if (> (length arg) 2)
+ − 863 `(progn ,(cadr arg) (list ,@(cddr arg)))
+ − 864 (cadr arg)))
+ − 865 (t
+ − 866 (byte-optimize-predicate form)))))
+ − 867
428
+ − 868 (put 'identity 'byte-optimizer 'byte-optimize-identity)
+ − 869
+ − 870 (put '+ 'byte-optimizer 'byte-optimize-plus)
+ − 871 (put '* 'byte-optimizer 'byte-optimize-multiply)
+ − 872 (put '- 'byte-optimizer 'byte-optimize-minus)
+ − 873 (put '/ 'byte-optimizer 'byte-optimize-divide)
446
+ − 874 (put '% 'byte-optimizer 'byte-optimize-predicate)
428
+ − 875 (put 'max 'byte-optimizer 'byte-optimize-associative-math)
+ − 876 (put 'min 'byte-optimizer 'byte-optimize-associative-math)
+ − 877
+ − 878 (put 'eq 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 879 (put 'eql 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 880 (put 'equal 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 881 (put 'string= 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 882 (put 'string-equal 'byte-optimizer 'byte-optimize-binary-predicate)
+ − 883
550
+ − 884 (put '= 'byte-optimizer 'byte-optimize-predicate)
428
+ − 885 (put '< 'byte-optimizer 'byte-optimize-predicate)
+ − 886 (put '> 'byte-optimizer 'byte-optimize-predicate)
+ − 887 (put '<= 'byte-optimizer 'byte-optimize-predicate)
+ − 888 (put '>= 'byte-optimizer 'byte-optimize-predicate)
+ − 889 (put '1+ 'byte-optimizer 'byte-optimize-predicate)
+ − 890 (put '1- 'byte-optimizer 'byte-optimize-predicate)
+ − 891 (put 'not 'byte-optimizer 'byte-optimize-predicate)
+ − 892 (put 'null 'byte-optimizer 'byte-optimize-predicate)
+ − 893 (put 'memq 'byte-optimizer 'byte-optimize-predicate)
+ − 894 (put 'consp 'byte-optimizer 'byte-optimize-predicate)
+ − 895 (put 'listp 'byte-optimizer 'byte-optimize-predicate)
+ − 896 (put 'symbolp 'byte-optimizer 'byte-optimize-predicate)
+ − 897 (put 'stringp 'byte-optimizer 'byte-optimize-predicate)
+ − 898 (put 'string< 'byte-optimizer 'byte-optimize-predicate)
+ − 899 (put 'string-lessp 'byte-optimizer 'byte-optimize-predicate)
440
+ − 900 (put 'length 'byte-optimizer 'byte-optimize-predicate)
428
+ − 901
+ − 902 (put 'logand 'byte-optimizer 'byte-optimize-logmumble)
+ − 903 (put 'logior 'byte-optimizer 'byte-optimize-logmumble)
+ − 904 (put 'logxor 'byte-optimizer 'byte-optimize-logmumble)
+ − 905 (put 'lognot 'byte-optimizer 'byte-optimize-predicate)
+ − 906
444
+ − 907 (put 'car 'byte-optimizer 'byte-optimize-car)
+ − 908 (put 'cdr 'byte-optimizer 'byte-optimize-cdr)
428
+ − 909 (put 'car-safe 'byte-optimizer 'byte-optimize-predicate)
+ − 910 (put 'cdr-safe 'byte-optimizer 'byte-optimize-predicate)
+ − 911
+ − 912
440
+ − 913 ;; I'm not convinced that this is necessary. Doesn't the optimizer loop
428
+ − 914 ;; take care of this? - Jamie
+ − 915 ;; I think this may some times be necessary to reduce eg. (quote 5) to 5,
+ − 916 ;; so arithmetic optimizers recognize the numeric constant. - Hallvard
+ − 917 (put 'quote 'byte-optimizer 'byte-optimize-quote)
+ − 918 (defun byte-optimize-quote (form)
+ − 919 (if (or (consp (nth 1 form))
+ − 920 (and (symbolp (nth 1 form))
+ − 921 ;; XEmacs addition:
+ − 922 (not (keywordp (nth 1 form)))
+ − 923 (not (memq (nth 1 form) '(nil t)))))
+ − 924 form
+ − 925 (nth 1 form)))
+ − 926
+ − 927 (defun byte-optimize-zerop (form)
+ − 928 (cond ((numberp (nth 1 form))
+ − 929 (eval form))
+ − 930 (byte-compile-delete-errors
+ − 931 (list '= (nth 1 form) 0))
+ − 932 (form)))
+ − 933
+ − 934 (put 'zerop 'byte-optimizer 'byte-optimize-zerop)
+ − 935
+ − 936 (defun byte-optimize-and (form)
+ − 937 ;; Simplify if less than 2 args.
+ − 938 ;; if there is a literal nil in the args to `and', throw it and following
+ − 939 ;; forms away, and surround the `and' with (progn ... nil).
+ − 940 (cond ((null (cdr form)))
+ − 941 ((memq nil form)
+ − 942 (list 'progn
+ − 943 (byte-optimize-and
+ − 944 (prog1 (setq form (copy-sequence form))
+ − 945 (while (nth 1 form)
+ − 946 (setq form (cdr form)))
+ − 947 (setcdr form nil)))
+ − 948 nil))
+ − 949 ((null (cdr (cdr form)))
+ − 950 (nth 1 form))
+ − 951 ((byte-optimize-predicate form))))
+ − 952
+ − 953 (defun byte-optimize-or (form)
+ − 954 ;; Throw away nil's, and simplify if less than 2 args.
+ − 955 ;; If there is a literal non-nil constant in the args to `or', throw away all
+ − 956 ;; following forms.
+ − 957 (if (memq nil form)
+ − 958 (setq form (delq nil (copy-sequence form))))
+ − 959 (let ((rest form))
+ − 960 (while (cdr (setq rest (cdr rest)))
+ − 961 (if (byte-compile-trueconstp (car rest))
+ − 962 (setq form (copy-sequence form)
+ − 963 rest (setcdr (memq (car rest) form) nil))))
+ − 964 (if (cdr (cdr form))
+ − 965 (byte-optimize-predicate form)
+ − 966 (nth 1 form))))
+ − 967
1297
+ − 968 ;; END SYNC WITH 20.7.
+ − 969
448
+ − 970 ;;; For the byte optimizer, `cond' is just overly sweet syntactic sugar.
+ − 971 ;;; So we rewrite (cond ...) in terms of `if' and `or',
+ − 972 ;;; which are easier to optimize.
428
+ − 973 (defun byte-optimize-cond (form)
448
+ − 974 (byte-optimize-cond-1 (cdr form)))
+ − 975
+ − 976 (defun byte-optimize-cond-1 (clauses)
+ − 977 (cond
+ − 978 ((null clauses) nil)
+ − 979 ((consp (car clauses))
+ − 980 (nconc
+ − 981 (case (length (car clauses))
+ − 982 (1 `(or ,(nth 0 (car clauses))))
+ − 983 (2 `(if ,(nth 0 (car clauses)) ,(nth 1 (car clauses))))
+ − 984 (t `(if ,(nth 0 (car clauses)) (progn ,@(cdr (car clauses))))))
+ − 985 (when (cdr clauses) (list (byte-optimize-cond-1 (cdr clauses))))))
+ − 986 (t (error "malformed cond clause %s" (car clauses)))))
428
+ − 987
1297
+ − 988 ;; BEGIN SYNC WITH 20.7.
+ − 989
428
+ − 990 (defun byte-optimize-if (form)
+ − 991 ;; (if <true-constant> <then> <else...>) ==> <then>
+ − 992 ;; (if <false-constant> <then> <else...>) ==> (progn <else...>)
+ − 993 ;; (if <test> nil <else...>) ==> (if (not <test>) (progn <else...>))
+ − 994 ;; (if <test> <then> nil) ==> (if <test> <then>)
+ − 995 (let ((clause (nth 1 form)))
+ − 996 (cond ((byte-compile-trueconstp clause)
+ − 997 (nth 2 form))
+ − 998 ((null clause)
+ − 999 (if (nthcdr 4 form)
+ − 1000 (cons 'progn (nthcdr 3 form))
+ − 1001 (nth 3 form)))
+ − 1002 ((nth 2 form)
+ − 1003 (if (equal '(nil) (nthcdr 3 form))
+ − 1004 (list 'if clause (nth 2 form))
+ − 1005 form))
+ − 1006 ((or (nth 3 form) (nthcdr 4 form))
+ − 1007 (list 'if
+ − 1008 ;; Don't make a double negative;
+ − 1009 ;; instead, take away the one that is there.
+ − 1010 (if (and (consp clause) (memq (car clause) '(not null))
+ − 1011 (= (length clause) 2)) ; (not xxxx) or (not (xxxx))
+ − 1012 (nth 1 clause)
+ − 1013 (list 'not clause))
+ − 1014 (if (nthcdr 4 form)
+ − 1015 (cons 'progn (nthcdr 3 form))
+ − 1016 (nth 3 form))))
+ − 1017 (t
+ − 1018 (list 'progn clause nil)))))
+ − 1019
+ − 1020 (defun byte-optimize-while (form)
+ − 1021 (if (nth 1 form)
+ − 1022 form))
+ − 1023
+ − 1024 (put 'and 'byte-optimizer 'byte-optimize-and)
+ − 1025 (put 'or 'byte-optimizer 'byte-optimize-or)
+ − 1026 (put 'cond 'byte-optimizer 'byte-optimize-cond)
+ − 1027 (put 'if 'byte-optimizer 'byte-optimize-if)
+ − 1028 (put 'while 'byte-optimizer 'byte-optimize-while)
+ − 1029
446
+ − 1030 ;; The supply of bytecodes is small and constrained by backward compatibility.
+ − 1031 ;; Several functions have byte-coded versions and hence are very efficient.
+ − 1032 ;; Related functions which can be expressed in terms of the byte-coded
+ − 1033 ;; ones should be transformed into bytecoded calls for efficiency.
+ − 1034 ;; This is especially the case for functions with a backward- and
+ − 1035 ;; forward- version, but with a bytecode only for the forward one.
+ − 1036
+ − 1037 ;; Some programmers have hand-optimized calls like (backward-char)
+ − 1038 ;; into the call (forward-char -1).
+ − 1039 ;; But it's so much nicer for the byte-compiler to do this automatically!
+ − 1040
+ − 1041 ;; (char-before) ==> (char-after (1- (point)))
+ − 1042 (put 'char-before 'byte-optimizer 'byte-optimize-char-before)
434
+ − 1043 (defun byte-optimize-char-before (form)
446
+ − 1044 `(char-after
+ − 1045 ,(cond
+ − 1046 ((null (nth 1 form))
+ − 1047 '(1- (point)))
+ − 1048 ((equal '(point) (nth 1 form))
+ − 1049 '(1- (point)))
+ − 1050 (t `(1- (or ,(nth 1 form) (point)))))
+ − 1051 ,@(cdr (cdr form))))
+ − 1052
+ − 1053 ;; (backward-char n) ==> (forward-char (- n))
+ − 1054 (put 'backward-char 'byte-optimizer 'byte-optimize-backward-char)
+ − 1055 (defun byte-optimize-backward-char (form)
+ − 1056 `(forward-char
+ − 1057 ,(typecase (nth 1 form)
+ − 1058 (null -1)
+ − 1059 (integer (- (nth 1 form)))
+ − 1060 (t `(- (or ,(nth 1 form) 1))))
+ − 1061 ,@(cdr (cdr form))))
440
+ − 1062
446
+ − 1063 ;; (backward-word n) ==> (forward-word (- n))
+ − 1064 (put 'backward-word 'byte-optimizer 'byte-optimize-backward-word)
+ − 1065 (defun byte-optimize-backward-word (form)
+ − 1066 `(forward-word
+ − 1067 ,(typecase (nth 1 form)
+ − 1068 (null -1)
+ − 1069 (integer (- (nth 1 form)))
+ − 1070 (t `(- (or ,(nth 1 form) 1))))
+ − 1071 ,@(cdr (cdr form))))
+ − 1072
+ − 1073 ;; The following would be a valid optimization of the above kind, but
+ − 1074 ;; the gain in performance is very small, since the saved funcall is
+ − 1075 ;; counterbalanced by the necessity of adding a bytecode for (point).
+ − 1076 ;;
+ − 1077 ;; Also, users are more likely to have modified the behavior of
+ − 1078 ;; delete-char via advice or some similar mechanism. This is much
+ − 1079 ;; less of a problem for the previous functions because it wouldn't
+ − 1080 ;; make sense to modify the behaviour of `backward-char' without also
+ − 1081 ;; modifying `forward-char', for example.
+ − 1082
+ − 1083 ;; (delete-char n) ==> (delete-region (point) (+ (point) n))
+ − 1084 ;; (put 'delete-char 'byte-optimizer 'byte-optimize-delete-char)
+ − 1085 ;; (defun byte-optimize-delete-char (form)
+ − 1086 ;; (case (length (cdr form))
+ − 1087 ;; (0 `(delete-region (point) (1+ (point))))
+ − 1088 ;; (1 `(delete-region (point) (+ (point) ,(nth 1 form))))
+ − 1089 ;; (t form)))
434
+ − 1090
428
+ − 1091 ;; byte-compile-negation-optimizer lives in bytecomp.el
+ − 1092 ;(put '/= 'byte-optimizer 'byte-compile-negation-optimizer)
+ − 1093 (put 'atom 'byte-optimizer 'byte-compile-negation-optimizer)
+ − 1094 (put 'nlistp 'byte-optimizer 'byte-compile-negation-optimizer)
+ − 1095
+ − 1096 (defun byte-optimize-funcall (form)
+ − 1097 ;; (funcall '(lambda ...) ...) ==> ((lambda ...) ...)
+ − 1098 ;; (funcall 'foo ...) ==> (foo ...)
+ − 1099 (let ((fn (nth 1 form)))
+ − 1100 (if (memq (car-safe fn) '(quote function))
+ − 1101 (cons (nth 1 fn) (cdr (cdr form)))
+ − 1102 form)))
+ − 1103
+ − 1104 (defun byte-optimize-apply (form)
+ − 1105 ;; If the last arg is a literal constant, turn this into a funcall.
+ − 1106 ;; The funcall optimizer can then transform (funcall 'foo ...) -> (foo ...).
+ − 1107 (let ((fn (nth 1 form))
+ − 1108 (last (nth (1- (length form)) form))) ; I think this really is fastest
+ − 1109 (or (if (or (null last)
+ − 1110 (eq (car-safe last) 'quote))
+ − 1111 (if (listp (nth 1 last))
+ − 1112 (let ((butlast (nreverse (cdr (reverse (cdr (cdr form)))))))
+ − 1113 (nconc (list 'funcall fn) butlast
+ − 1114 (mapcar #'(lambda (x) (list 'quote x)) (nth 1 last))))
+ − 1115 (byte-compile-warn
+ − 1116 "last arg to apply can't be a literal atom: %s"
+ − 1117 (prin1-to-string last))
+ − 1118 nil))
+ − 1119 form)))
+ − 1120
+ − 1121 (put 'funcall 'byte-optimizer 'byte-optimize-funcall)
+ − 1122 (put 'apply 'byte-optimizer 'byte-optimize-apply)
+ − 1123
+ − 1124
+ − 1125 (put 'let 'byte-optimizer 'byte-optimize-letX)
+ − 1126 (put 'let* 'byte-optimizer 'byte-optimize-letX)
+ − 1127 (defun byte-optimize-letX (form)
+ − 1128 (cond ((null (nth 1 form))
+ − 1129 ;; No bindings
+ − 1130 (cons 'progn (cdr (cdr form))))
+ − 1131 ((or (nth 2 form) (nthcdr 3 form))
+ − 1132 form)
+ − 1133 ;; The body is nil
+ − 1134 ((eq (car form) 'let)
+ − 1135 (append '(progn) (mapcar 'car-safe (mapcar 'cdr-safe (nth 1 form)))
+ − 1136 '(nil)))
+ − 1137 (t
+ − 1138 (let ((binds (reverse (nth 1 form))))
+ − 1139 (list 'let* (reverse (cdr binds)) (nth 1 (car binds)) nil)))))
+ − 1140
+ − 1141
+ − 1142 (put 'nth 'byte-optimizer 'byte-optimize-nth)
+ − 1143 (defun byte-optimize-nth (form)
+ − 1144 (if (and (= (safe-length form) 3) (memq (nth 1 form) '(0 1)))
+ − 1145 (list 'car (if (zerop (nth 1 form))
+ − 1146 (nth 2 form)
+ − 1147 (list 'cdr (nth 2 form))))
+ − 1148 (byte-optimize-predicate form)))
+ − 1149
+ − 1150 (put 'nthcdr 'byte-optimizer 'byte-optimize-nthcdr)
+ − 1151 (defun byte-optimize-nthcdr (form)
+ − 1152 (if (and (= (safe-length form) 3) (not (memq (nth 1 form) '(0 1 2))))
+ − 1153 (byte-optimize-predicate form)
+ − 1154 (let ((count (nth 1 form)))
+ − 1155 (setq form (nth 2 form))
+ − 1156 (while (>= (setq count (1- count)) 0)
+ − 1157 (setq form (list 'cdr form)))
+ − 1158 form)))
444
+ − 1159
+ − 1160 (put 'concat 'byte-optimizer 'byte-optimize-concat)
+ − 1161 (defun byte-optimize-concat (form)
+ − 1162 (let ((args (cdr form))
+ − 1163 (constant t))
+ − 1164 (while (and args constant)
+ − 1165 (or (byte-compile-constp (car args))
+ − 1166 (setq constant nil))
+ − 1167 (setq args (cdr args)))
+ − 1168 (if constant
+ − 1169 (eval form)
+ − 1170 form)))
428
+ − 1171
440
+ − 1172 ;;; enumerating those functions which need not be called if the returned
428
+ − 1173 ;;; value is not used. That is, something like
+ − 1174 ;;; (progn (list (something-with-side-effects) (yow))
+ − 1175 ;;; (foo))
+ − 1176 ;;; may safely be turned into
+ − 1177 ;;; (progn (progn (something-with-side-effects) (yow))
+ − 1178 ;;; (foo))
+ − 1179 ;;; Further optimizations will turn (progn (list 1 2 3) 'foo) into 'foo.
+ − 1180
+ − 1181 ;;; I wonder if I missed any :-\)
+ − 1182 (let ((side-effect-free-fns
+ − 1183 '(% * + - / /= 1+ 1- < <= = > >= abs acos append aref ash asin atan
+ − 1184 assoc assq
+ − 1185 boundp buffer-file-name buffer-local-variables buffer-modified-p
+ − 1186 buffer-substring
+ − 1187 capitalize car-less-than-car car cdr ceiling concat
+ − 1188 ;; coordinates-in-window-p not in XEmacs
+ − 1189 copy-marker cos count-lines
+ − 1190 default-boundp default-value documentation downcase
+ − 1191 elt exp expt fboundp featurep
+ − 1192 file-directory-p file-exists-p file-locked-p file-name-absolute-p
+ − 1193 file-newer-than-file-p file-readable-p file-symlink-p file-writable-p
+ − 1194 float floor format
+ − 1195 get get-buffer get-buffer-window getenv get-file-buffer
+ − 1196 ;; hash-table functions
+ − 1197 make-hash-table copy-hash-table
+ − 1198 gethash
+ − 1199 hash-table-count
+ − 1200 hash-table-rehash-size
+ − 1201 hash-table-rehash-threshold
+ − 1202 hash-table-size
+ − 1203 hash-table-test
+ − 1204 hash-table-type
+ − 1205 ;;
+ − 1206 int-to-string
+ − 1207 length log log10 logand logb logior lognot logxor lsh
+ − 1208 marker-buffer max member memq min mod
+ − 1209 next-window nth nthcdr number-to-string
440
+ − 1210 parse-colon-path plist-get previous-window
428
+ − 1211 radians-to-degrees rassq regexp-quote reverse round
+ − 1212 sin sqrt string< string= string-equal string-lessp string-to-char
+ − 1213 string-to-int string-to-number substring symbol-plist
+ − 1214 tan upcase user-variable-p vconcat
+ − 1215 ;; XEmacs change: window-edges -> window-pixel-edges
+ − 1216 window-buffer window-dedicated-p window-pixel-edges window-height
+ − 1217 window-hscroll window-minibuffer-p window-width
+ − 1218 zerop
+ − 1219 ;; functions defined by cl
+ − 1220 oddp evenp plusp minusp
+ − 1221 abs expt signum last butlast ldiff
+ − 1222 pairlis gcd lcm
+ − 1223 isqrt floor* ceiling* truncate* round* mod* rem* subseq
440
+ − 1224 list-length getf
428
+ − 1225 ))
+ − 1226 (side-effect-and-error-free-fns
+ − 1227 '(arrayp atom
+ − 1228 bobp bolp buffer-end buffer-list buffer-size buffer-string bufferp
+ − 1229 car-safe case-table-p cdr-safe char-or-string-p char-table-p
+ − 1230 characterp commandp cons
+ − 1231 consolep console-live-p consp
+ − 1232 current-buffer
+ − 1233 ;; XEmacs: extent functions, frame-live-p, various other stuff
+ − 1234 devicep device-live-p
+ − 1235 dot dot-marker eobp eolp eq eql equal eventp extentp
+ − 1236 extent-live-p floatp framep frame-live-p
+ − 1237 get-largest-window get-lru-window
+ − 1238 hash-table-p
+ − 1239 identity ignore integerp integer-or-marker-p interactive-p
+ − 1240 invocation-directory invocation-name
444
+ − 1241 keymapp list listp
428
+ − 1242 make-marker mark mark-marker markerp memory-limit minibuffer-window
+ − 1243 ;; mouse-movement-p not in XEmacs
+ − 1244 natnump nlistp not null number-or-marker-p numberp
+ − 1245 one-window-p ;; overlayp not in XEmacs
+ − 1246 point point-marker point-min point-max processp
+ − 1247 range-table-p
+ − 1248 selected-window sequencep stringp subrp symbolp syntax-table-p
+ − 1249 user-full-name user-login-name user-original-login-name
+ − 1250 user-real-login-name user-real-uid user-uid
+ − 1251 vector vectorp
+ − 1252 window-configuration-p window-live-p windowp
+ − 1253 ;; Functions defined by cl
+ − 1254 eql floatp-safe list* subst acons equalp random-state-p
+ − 1255 copy-tree sublis
+ − 1256 )))
+ − 1257 (dolist (fn side-effect-free-fns)
+ − 1258 (put fn 'side-effect-free t))
+ − 1259 (dolist (fn side-effect-and-error-free-fns)
+ − 1260 (put fn 'side-effect-free 'error-free)))
+ − 1261
+ − 1262
+ − 1263 (defun byte-compile-splice-in-already-compiled-code (form)
+ − 1264 ;; form is (byte-code "..." [...] n)
446
+ − 1265 (if (not (memq byte-optimize '(t byte)))
428
+ − 1266 (byte-compile-normal-call form)
+ − 1267 (byte-inline-lapcode
+ − 1268 (byte-decompile-bytecode-1 (nth 1 form) (nth 2 form) t))
+ − 1269 (setq byte-compile-maxdepth (max (+ byte-compile-depth (nth 3 form))
+ − 1270 byte-compile-maxdepth))
+ − 1271 (setq byte-compile-depth (1+ byte-compile-depth))))
+ − 1272
+ − 1273 (put 'byte-code 'byte-compile 'byte-compile-splice-in-already-compiled-code)
+ − 1274
+ − 1275
+ − 1276 (defconst byte-constref-ops
+ − 1277 '(byte-constant byte-constant2 byte-varref byte-varset byte-varbind))
+ − 1278
+ − 1279 ;;; This function extracts the bitfields from variable-length opcodes.
+ − 1280 ;;; Originally defined in disass.el (which no longer uses it.)
+ − 1281
+ − 1282 (defun disassemble-offset ()
+ − 1283 "Don't call this!"
+ − 1284 ;; fetch and return the offset for the current opcode.
+ − 1285 ;; return NIL if this opcode has no offset
+ − 1286 ;; OP, PTR and BYTES are used and set dynamically
442
+ − 1287 (declare (special op ptr bytes))
428
+ − 1288 (cond ((< op byte-nth)
+ − 1289 (let ((tem (logand op 7)))
+ − 1290 (setq op (logand op 248))
+ − 1291 (cond ((eq tem 6)
+ − 1292 (setq ptr (1+ ptr)) ;offset in next byte
+ − 1293 ;; char-to-int to avoid downstream problems
+ − 1294 ;; caused by chars appearing where ints are
+ − 1295 ;; expected. In bytecode the bytes in the
+ − 1296 ;; opcode string are always interpreted as ints.
+ − 1297 (char-to-int (aref bytes ptr)))
+ − 1298 ((eq tem 7)
+ − 1299 (setq ptr (1+ ptr)) ;offset in next 2 bytes
+ − 1300 (+ (aref bytes ptr)
+ − 1301 (progn (setq ptr (1+ ptr))
+ − 1302 (lsh (aref bytes ptr) 8))))
+ − 1303 (t tem)))) ;offset was in opcode
+ − 1304 ((>= op byte-constant)
+ − 1305 (prog1 (- op byte-constant) ;offset in opcode
+ − 1306 (setq op byte-constant)))
+ − 1307 ((and (>= op byte-constant2)
+ − 1308 (<= op byte-goto-if-not-nil-else-pop))
+ − 1309 (setq ptr (1+ ptr)) ;offset in next 2 bytes
+ − 1310 (+ (aref bytes ptr)
+ − 1311 (progn (setq ptr (1+ ptr))
+ − 1312 (lsh (aref bytes ptr) 8))))
+ − 1313 ;; XEmacs: this code was here before. FSF's first comparison
+ − 1314 ;; is (>= op byte-listN). It appears that the rel-goto stuff
+ − 1315 ;; does not exist in FSF 19.30. It doesn't exist in 19.28
+ − 1316 ;; either, so I'm going to assume that this is an improvement
+ − 1317 ;; on our part and leave it in. --ben
+ − 1318 ((and (>= op byte-rel-goto)
+ − 1319 (<= op byte-insertN))
+ − 1320 (setq ptr (1+ ptr)) ;offset in next byte
+ − 1321 ;; Use char-to-int to avoid downstream problems caused by
+ − 1322 ;; chars appearing where ints are expected. In bytecode
+ − 1323 ;; the bytes in the opcode string are always interpreted as
+ − 1324 ;; ints.
+ − 1325 (char-to-int (aref bytes ptr)))))
+ − 1326
+ − 1327
+ − 1328 ;;; This de-compiler is used for inline expansion of compiled functions,
+ − 1329 ;;; and by the disassembler.
+ − 1330 ;;;
+ − 1331 ;;; This list contains numbers, which are pc values,
+ − 1332 ;;; before each instruction.
+ − 1333 (defun byte-decompile-bytecode (bytes constvec)
+ − 1334 "Turns BYTECODE into lapcode, referring to CONSTVEC."
+ − 1335 (let ((byte-compile-constants nil)
+ − 1336 (byte-compile-variables nil)
+ − 1337 (byte-compile-tag-number 0))
+ − 1338 (byte-decompile-bytecode-1 bytes constvec)))
+ − 1339
+ − 1340 ;; As byte-decompile-bytecode, but updates
+ − 1341 ;; byte-compile-{constants, variables, tag-number}.
+ − 1342 ;; If MAKE-SPLICEABLE is true, then `return' opcodes are replaced
+ − 1343 ;; with `goto's destined for the end of the code.
+ − 1344 ;; That is for use by the compiler.
+ − 1345 ;; If MAKE-SPLICEABLE is nil, we are being called for the disassembler.
+ − 1346 ;; In that case, we put a pc value into the list
+ − 1347 ;; before each insn (or its label).
+ − 1348 (defun byte-decompile-bytecode-1 (bytes constvec &optional make-spliceable)
+ − 1349 (let ((length (length bytes))
+ − 1350 (ptr 0) optr tags op offset
+ − 1351 ;; tag unused
+ − 1352 lap tmp
+ − 1353 endtag
+ − 1354 ;; (retcount 0) unused
+ − 1355 )
+ − 1356 (while (not (= ptr length))
+ − 1357 (or make-spliceable
+ − 1358 (setq lap (cons ptr lap)))
+ − 1359 (setq op (aref bytes ptr)
+ − 1360 optr ptr
+ − 1361 offset (disassemble-offset)) ; this does dynamic-scope magic
+ − 1362 (setq op (aref byte-code-vector op))
+ − 1363 ;; XEmacs: the next line in FSF 19.30 reads
+ − 1364 ;; (cond ((memq op byte-goto-ops)
+ − 1365 ;; see the comment above about byte-rel-goto in XEmacs.
+ − 1366 (cond ((or (memq op byte-goto-ops)
+ − 1367 (cond ((memq op byte-rel-goto-ops)
+ − 1368 (setq op (aref byte-code-vector
+ − 1369 (- (symbol-value op)
+ − 1370 (- byte-rel-goto byte-goto))))
+ − 1371 (setq offset (+ ptr (- offset 127)))
+ − 1372 t)))
+ − 1373 ;; it's a pc
+ − 1374 (setq offset
+ − 1375 (cdr (or (assq offset tags)
+ − 1376 (car (setq tags
+ − 1377 (cons (cons offset
+ − 1378 (byte-compile-make-tag))
+ − 1379 tags)))))))
+ − 1380 ((cond ((eq op 'byte-constant2) (setq op 'byte-constant) t)
+ − 1381 ((memq op byte-constref-ops)))
1297
+ − 1382 (setq tmp (if (>= offset (length constvec))
+ − 1383 (list 'out-of-range offset)
+ − 1384 (aref constvec offset))
428
+ − 1385 offset (if (eq op 'byte-constant)
+ − 1386 (byte-compile-get-constant tmp)
+ − 1387 (or (assq tmp byte-compile-variables)
+ − 1388 (car (setq byte-compile-variables
+ − 1389 (cons (list tmp)
+ − 1390 byte-compile-variables)))))))
+ − 1391 ((and make-spliceable
+ − 1392 (eq op 'byte-return))
+ − 1393 (if (= ptr (1- length))
+ − 1394 (setq op nil)
+ − 1395 (setq offset (or endtag (setq endtag (byte-compile-make-tag)))
+ − 1396 op 'byte-goto))))
+ − 1397 ;; lap = ( [ (pc . (op . arg)) ]* )
+ − 1398 (setq lap (cons (cons optr (cons op (or offset 0)))
+ − 1399 lap))
+ − 1400 (setq ptr (1+ ptr)))
+ − 1401 ;; take off the dummy nil op that we replaced a trailing "return" with.
+ − 1402 (let ((rest lap))
+ − 1403 (while rest
+ − 1404 (cond ((numberp (car rest)))
+ − 1405 ((setq tmp (assq (car (car rest)) tags))
+ − 1406 ;; this addr is jumped to
+ − 1407 (setcdr rest (cons (cons nil (cdr tmp))
+ − 1408 (cdr rest)))
+ − 1409 (setq tags (delq tmp tags))
+ − 1410 (setq rest (cdr rest))))
+ − 1411 (setq rest (cdr rest))))
+ − 1412 (if tags (error "optimizer error: missed tags %s" tags))
+ − 1413 (if (null (car (cdr (car lap))))
+ − 1414 (setq lap (cdr lap)))
+ − 1415 (if endtag
+ − 1416 (setq lap (cons (cons nil endtag) lap)))
+ − 1417 ;; remove addrs, lap = ( [ (op . arg) | (TAG tagno) ]* )
+ − 1418 (mapcar #'(lambda (elt) (if (numberp elt) elt (cdr elt)))
+ − 1419 (nreverse lap))))
+ − 1420
+ − 1421
+ − 1422 ;;; peephole optimizer
+ − 1423
+ − 1424 (defconst byte-tagref-ops (cons 'TAG byte-goto-ops))
+ − 1425
+ − 1426 (defconst byte-conditional-ops
+ − 1427 '(byte-goto-if-nil byte-goto-if-not-nil byte-goto-if-nil-else-pop
+ − 1428 byte-goto-if-not-nil-else-pop))
+ − 1429
+ − 1430 (defconst byte-after-unbind-ops
+ − 1431 '(byte-constant byte-dup
+ − 1432 byte-symbolp byte-consp byte-stringp byte-listp byte-numberp byte-integerp
444
+ − 1433 byte-eq byte-not
428
+ − 1434 byte-cons byte-list1 byte-list2 ; byte-list3 byte-list4
+ − 1435 byte-interactive-p)
+ − 1436 ;; How about other side-effect-free-ops? Is it safe to move an
+ − 1437 ;; error invocation (such as from nth) out of an unwind-protect?
444
+ − 1438 ;; No, it is not, because the unwind-protect forms can alter
+ − 1439 ;; the inside of the object to which nth would apply.
+ − 1440 ;; For the same reason, byte-equal was deleted from this list.
428
+ − 1441 "Byte-codes that can be moved past an unbind.")
+ − 1442
+ − 1443 (defconst byte-compile-side-effect-and-error-free-ops
+ − 1444 '(byte-constant byte-dup byte-symbolp byte-consp byte-stringp byte-listp
+ − 1445 byte-integerp byte-numberp byte-eq byte-equal byte-not byte-car-safe
+ − 1446 byte-cdr-safe byte-cons byte-list1 byte-list2 byte-point byte-point-max
+ − 1447 byte-point-min byte-following-char byte-preceding-char
+ − 1448 byte-current-column byte-eolp byte-eobp byte-bolp byte-bobp
+ − 1449 byte-current-buffer byte-interactive-p))
+ − 1450
+ − 1451 (defconst byte-compile-side-effect-free-ops
440
+ − 1452 (nconc
428
+ − 1453 '(byte-varref byte-nth byte-memq byte-car byte-cdr byte-length byte-aref
+ − 1454 byte-symbol-value byte-get byte-concat2 byte-concat3 byte-sub1 byte-add1
+ − 1455 byte-eqlsign byte-gtr byte-lss byte-leq byte-geq byte-diff byte-negate
+ − 1456 byte-plus byte-max byte-min byte-mult byte-char-after byte-char-syntax
+ − 1457 byte-buffer-substring byte-string= byte-string< byte-nthcdr byte-elt
+ − 1458 byte-member byte-assq byte-quo byte-rem)
+ − 1459 byte-compile-side-effect-and-error-free-ops))
+ − 1460
+ − 1461 ;;; This piece of shit is because of the way DEFVAR_BOOL() variables work.
+ − 1462 ;;; Consider the code
+ − 1463 ;;;
+ − 1464 ;;; (defun foo (flag)
+ − 1465 ;;; (let ((old-pop-ups pop-up-windows)
+ − 1466 ;;; (pop-up-windows flag))
+ − 1467 ;;; (cond ((not (eq pop-up-windows old-pop-ups))
+ − 1468 ;;; (setq old-pop-ups pop-up-windows)
+ − 1469 ;;; ...))))
+ − 1470 ;;;
+ − 1471 ;;; Uncompiled, old-pop-ups will always be set to nil or t, even if FLAG is
+ − 1472 ;;; something else. But if we optimize
+ − 1473 ;;;
+ − 1474 ;;; varref flag
+ − 1475 ;;; varbind pop-up-windows
+ − 1476 ;;; varref pop-up-windows
+ − 1477 ;;; not
+ − 1478 ;;; to
+ − 1479 ;;; varref flag
+ − 1480 ;;; dup
+ − 1481 ;;; varbind pop-up-windows
+ − 1482 ;;; not
+ − 1483 ;;;
440
+ − 1484 ;;; we break the program, because it will appear that pop-up-windows and
428
+ − 1485 ;;; old-pop-ups are not EQ when really they are. So we have to know what
+ − 1486 ;;; the BOOL variables are, and not perform this optimization on them.
+ − 1487 ;;;
+ − 1488
+ − 1489 ;;; This used to hold a large list of boolean variables, which had to
+ − 1490 ;;; be updated every time a new DEFVAR_BOOL is added, making it very
+ − 1491 ;;; hard to maintain. Such a list is not necessary under XEmacs,
+ − 1492 ;;; where we can use `built-in-variable-type' to query for boolean
+ − 1493 ;;; variables.
+ − 1494
+ − 1495 ;(defconst byte-boolean-vars
1297
+ − 1496 ; ...)
428
+ − 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))
1297
+ − 1957 (if (memq (car lap0) byte-constref-ops)
+ − 1958 (if (not (eq (car lap0) 'byte-constant))
+ − 1959 (progn
+ − 1960 (incf (gethash (cdr lap0) variable-frequency 0))
+ − 1961 (or (memq (cdr lap0) byte-compile-variables)
+ − 1962 (setq byte-compile-variables
+ − 1963 (cons (cdr lap0) byte-compile-variables))))
+ − 1964 (or (memq (cdr lap0) byte-compile-constants)
+ − 1965 (setq byte-compile-constants (cons (cdr lap0)
+ − 1966 byte-compile-constants)))))
428
+ − 1967 (cond (;;
442
+ − 1968 ;; const-C varset-X const-C --> const-C dup varset-X
428
+ − 1969 ;; const-C varbind-X const-C --> const-C dup varbind-X
+ − 1970 ;;
+ − 1971 (and (eq (car lap0) 'byte-constant)
+ − 1972 (eq (car (nth 2 rest)) 'byte-constant)
442
+ − 1973 (eq (cdr lap0) (cdr (nth 2 rest)))
428
+ − 1974 (memq (car lap1) '(byte-varbind byte-varset)))
+ − 1975 (byte-compile-log-lap " %s %s %s\t-->\t%s dup %s"
+ − 1976 lap0 lap1 lap0 lap0 lap1)
+ − 1977 (setcar (cdr (cdr rest)) (cons (car lap1) (cdr lap1)))
+ − 1978 (setcar (cdr rest) (cons 'byte-dup 0))
+ − 1979 (setq add-depth 1))
+ − 1980 ;;
+ − 1981 ;; const-X [dup/const-X ...] --> const-X [dup ...] dup
+ − 1982 ;; varref-X [dup/varref-X ...] --> varref-X [dup ...] dup
+ − 1983 ;;
+ − 1984 ((memq (car lap0) '(byte-constant byte-varref))
+ − 1985 (setq tmp rest
+ − 1986 tmp2 nil)
+ − 1987 (while (progn
+ − 1988 (while (eq 'byte-dup (car (car (setq tmp (cdr tmp))))))
+ − 1989 (and (eq (cdr lap0) (cdr (car tmp)))
+ − 1990 (eq (car lap0) (car (car tmp)))))
+ − 1991 (setcar tmp (cons 'byte-dup 0))
+ − 1992 (setq tmp2 t))
+ − 1993 (if tmp2
+ − 1994 (byte-compile-log-lap
+ − 1995 " %s [dup/%s]...\t-->\t%s dup..." lap0 lap0 lap0)))
+ − 1996 ;;
+ − 1997 ;; unbind-N unbind-M --> unbind-(N+M)
+ − 1998 ;;
+ − 1999 ((and (eq 'byte-unbind (car lap0))
+ − 2000 (eq 'byte-unbind (car lap1)))
+ − 2001 (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1
+ − 2002 (cons 'byte-unbind
+ − 2003 (+ (cdr lap0) (cdr lap1))))
+ − 2004 (setq keep-going t)
+ − 2005 (setq lap (delq lap0 lap))
+ − 2006 (setcdr lap1 (+ (cdr lap1) (cdr lap0))))
+ − 2007 )
+ − 2008 (setq rest (cdr rest)))
442
+ − 2009 ;; Since the first 6 entries of the compiled-function constants
+ − 2010 ;; vector are most efficient for varref/set/bind ops, we sort by
+ − 2011 ;; reference count. This generates maximally space efficient and
+ − 2012 ;; pretty time-efficient byte-code. See `byte-compile-constants-vector'.
+ − 2013 (setq byte-compile-variables
+ − 2014 (sort byte-compile-variables
+ − 2015 #'(lambda (v1 v2)
+ − 2016 (< (gethash v1 variable-frequency)
+ − 2017 (gethash v2 variable-frequency)))))
+ − 2018 ;; Another hack - put the most used variable in position 6, for
+ − 2019 ;; better locality of reference with adjoining constants.
+ − 2020 (let ((tail (last byte-compile-variables 6)))
+ − 2021 (setq byte-compile-variables
+ − 2022 (append (nbutlast byte-compile-variables 6)
+ − 2023 (nreverse tail))))
428
+ − 2024 (setq byte-compile-maxdepth (+ byte-compile-maxdepth add-depth)))
+ − 2025 lap)
+ − 2026
+ − 2027 (provide 'byte-optimize)
+ − 2028
+ − 2029
+ − 2030 ;; To avoid "lisp nesting exceeds max-lisp-eval-depth" when this file compiles
+ − 2031 ;; itself, compile some of its most used recursive functions (at load time).
+ − 2032 ;;
+ − 2033 (eval-when-compile
+ − 2034 (or (compiled-function-p (symbol-function 'byte-optimize-form))
+ − 2035 (assq 'byte-code (symbol-function 'byte-optimize-form))
+ − 2036 (let ((byte-optimize nil)
+ − 2037 (byte-compile-warnings nil))
+ − 2038 (mapcar
+ − 2039 #'(lambda (x)
+ − 2040 (or noninteractive (message "compiling %s..." x))
+ − 2041 (byte-compile x)
+ − 2042 (or noninteractive (message "compiling %s...done" x)))
+ − 2043 '(byte-optimize-form
+ − 2044 byte-optimize-body
+ − 2045 byte-optimize-predicate
+ − 2046 byte-optimize-binary-predicate
+ − 2047 ;; Inserted some more than necessary, to speed it up.
+ − 2048 byte-optimize-form-code-walker
+ − 2049 byte-optimize-lapcode))))
+ − 2050 nil)
+ − 2051
1297
+ − 2052 ;; END SYNC WITH 20.7.
+ − 2053
428
+ − 2054 ;;; byte-optimize.el ends here