comparison lisp/emacs-lisp/byte-opt.el @ 14169:83f275dcd93a

Update FSF's address.
author Erik Naggum <erik@naggum.no>
date Sun, 14 Jan 1996 07:34:30 +0000
parents 10c76db77107
children 4706508583bd
comparison
equal deleted inserted replaced
14168:3b925cc52931 14169:83f275dcd93a
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details. 19 ;; GNU General Public License for more details.
20 20
21 ;; You should have received a copy of the GNU General Public License 21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to 22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
24 25
25 ;;; Commentary: 26 ;;; Commentary:
26 27
27 ;;; ======================================================================== 28 ;; ========================================================================
28 ;;; "No matter how hard you try, you can't make a racehorse out of a pig. 29 ;; "No matter how hard you try, you can't make a racehorse out of a pig.
29 ;;; You can, however, make a faster pig." 30 ;; You can, however, make a faster pig."
30 ;;; 31 ;;
31 ;;; Or, to put it another way, the emacs byte compiler is a VW Bug. This code 32 ;; Or, to put it another way, the emacs byte compiler is a VW Bug. This code
32 ;;; makes it be a VW Bug with fuel injection and a turbocharger... You're 33 ;; makes it be a VW Bug with fuel injection and a turbocharger... You're
33 ;;; still not going to make it go faster than 70 mph, but it might be easier 34 ;; still not going to make it go faster than 70 mph, but it might be easier
34 ;;; to get it there. 35 ;; to get it there.
35 ;;; 36 ;;
36 37
37 ;;; TO DO: 38 ;; TO DO:
38 ;;; 39 ;;
39 ;;; (apply '(lambda (x &rest y) ...) 1 (foo)) 40 ;; (apply '(lambda (x &rest y) ...) 1 (foo))
40 ;;; 41 ;;
41 ;;; maintain a list of functions known not to access any global variables 42 ;; maintain a list of functions known not to access any global variables
42 ;;; (actually, give them a 'dynamically-safe property) and then 43 ;; (actually, give them a 'dynamically-safe property) and then
43 ;;; (let ( v1 v2 ... vM vN ) <...dynamically-safe...> ) ==> 44 ;; (let ( v1 v2 ... vM vN ) <...dynamically-safe...> ) ==>
44 ;;; (let ( v1 v2 ... vM ) vN <...dynamically-safe...> ) 45 ;; (let ( v1 v2 ... vM ) vN <...dynamically-safe...> )
45 ;;; by recursing on this, we might be able to eliminate the entire let. 46 ;; by recursing on this, we might be able to eliminate the entire let.
46 ;;; However certain variables should never have their bindings optimized 47 ;; However certain variables should never have their bindings optimized
47 ;;; away, because they affect everything. 48 ;; away, because they affect everything.
48 ;;; (put 'debug-on-error 'binding-is-magic t) 49 ;; (put 'debug-on-error 'binding-is-magic t)
49 ;;; (put 'debug-on-abort 'binding-is-magic t) 50 ;; (put 'debug-on-abort 'binding-is-magic t)
50 ;;; (put 'debug-on-next-call 'binding-is-magic t) 51 ;; (put 'debug-on-next-call 'binding-is-magic t)
51 ;;; (put 'mocklisp-arguments 'binding-is-magic t) 52 ;; (put 'mocklisp-arguments 'binding-is-magic t)
52 ;;; (put 'inhibit-quit 'binding-is-magic t) 53 ;; (put 'inhibit-quit 'binding-is-magic t)
53 ;;; (put 'quit-flag 'binding-is-magic t) 54 ;; (put 'quit-flag 'binding-is-magic t)
54 ;;; (put 't 'binding-is-magic t) 55 ;; (put 't 'binding-is-magic t)
55 ;;; (put 'nil 'binding-is-magic t) 56 ;; (put 'nil 'binding-is-magic t)
56 ;;; possibly also 57 ;; possibly also
57 ;;; (put 'gc-cons-threshold 'binding-is-magic t) 58 ;; (put 'gc-cons-threshold 'binding-is-magic t)
58 ;;; (put 'track-mouse 'binding-is-magic t) 59 ;; (put 'track-mouse 'binding-is-magic t)
59 ;;; others? 60 ;; others?
60 ;;; 61 ;;
61 ;;; Simple defsubsts often produce forms like 62 ;; Simple defsubsts often produce forms like
62 ;;; (let ((v1 (f1)) (v2 (f2)) ...) 63 ;; (let ((v1 (f1)) (v2 (f2)) ...)
63 ;;; (FN v1 v2 ...)) 64 ;; (FN v1 v2 ...))
64 ;;; It would be nice if we could optimize this to 65 ;; It would be nice if we could optimize this to
65 ;;; (FN (f1) (f2) ...) 66 ;; (FN (f1) (f2) ...)
66 ;;; but we can't unless FN is dynamically-safe (it might be dynamically 67 ;; but we can't unless FN is dynamically-safe (it might be dynamically
67 ;;; referring to the bindings that the lambda arglist established.) 68 ;; referring to the bindings that the lambda arglist established.)
68 ;;; One of the uncountable lossages introduced by dynamic scope... 69 ;; One of the uncountable lossages introduced by dynamic scope...
69 ;;; 70 ;;
70 ;;; Maybe there should be a control-structure that says "turn on 71 ;; Maybe there should be a control-structure that says "turn on
71 ;;; fast-and-loose type-assumptive optimizations here." Then when 72 ;; fast-and-loose type-assumptive optimizations here." Then when
72 ;;; we see a form like (car foo) we can from then on assume that 73 ;; we see a form like (car foo) we can from then on assume that
73 ;;; the variable foo is of type cons, and optimize based on that. 74 ;; the variable foo is of type cons, and optimize based on that.
74 ;;; But, this won't win much because of (you guessed it) dynamic 75 ;; But, this won't win much because of (you guessed it) dynamic
75 ;;; scope. Anything down the stack could change the value. 76 ;; scope. Anything down the stack could change the value.
76 ;;; (Another reason it doesn't work is that it is perfectly valid 77 ;; (Another reason it doesn't work is that it is perfectly valid
77 ;;; to call car with a null argument.) A better approach might 78 ;; to call car with a null argument.) A better approach might
78 ;;; be to allow type-specification of the form 79 ;; be to allow type-specification of the form
79 ;;; (put 'foo 'arg-types '(float (list integer) dynamic)) 80 ;; (put 'foo 'arg-types '(float (list integer) dynamic))
80 ;;; (put 'foo 'result-type 'bool) 81 ;; (put 'foo 'result-type 'bool)
81 ;;; It should be possible to have these types checked to a certain 82 ;; It should be possible to have these types checked to a certain
82 ;;; degree. 83 ;; degree.
83 ;;; 84 ;;
84 ;;; collapse common subexpressions 85 ;; collapse common subexpressions
85 ;;; 86 ;;
86 ;;; It would be nice if redundant sequences could be factored out as well, 87 ;; It would be nice if redundant sequences could be factored out as well,
87 ;;; when they are known to have no side-effects: 88 ;; when they are known to have no side-effects:
88 ;;; (list (+ a b c) (+ a b c)) --> a b add c add dup list-2 89 ;; (list (+ a b c) (+ a b c)) --> a b add c add dup list-2
89 ;;; but beware of traps like 90 ;; but beware of traps like
90 ;;; (cons (list x y) (list x y)) 91 ;; (cons (list x y) (list x y))
91 ;;; 92 ;;
92 ;;; Tail-recursion elimination is not really possible in Emacs Lisp. 93 ;; Tail-recursion elimination is not really possible in Emacs Lisp.
93 ;;; Tail-recursion elimination is almost always impossible when all variables 94 ;; Tail-recursion elimination is almost always impossible when all variables
94 ;;; have dynamic scope, but given that the "return" byteop requires the 95 ;; have dynamic scope, but given that the "return" byteop requires the
95 ;;; binding stack to be empty (rather than emptying it itself), there can be 96 ;; binding stack to be empty (rather than emptying it itself), there can be
96 ;;; no truly tail-recursive Emacs Lisp functions that take any arguments or 97 ;; no truly tail-recursive Emacs Lisp functions that take any arguments or
97 ;;; make any bindings. 98 ;; make any bindings.
98 ;;; 99 ;;
99 ;;; Here is an example of an Emacs Lisp function which could safely be 100 ;; Here is an example of an Emacs Lisp function which could safely be
100 ;;; byte-compiled tail-recursively: 101 ;; byte-compiled tail-recursively:
101 ;;; 102 ;;
102 ;;; (defun tail-map (fn list) 103 ;; (defun tail-map (fn list)
103 ;;; (cond (list 104 ;; (cond (list
104 ;;; (funcall fn (car list)) 105 ;; (funcall fn (car list))
105 ;;; (tail-map fn (cdr list))))) 106 ;; (tail-map fn (cdr list)))))
106 ;;; 107 ;;
107 ;;; However, if there was even a single let-binding around the COND, 108 ;; However, if there was even a single let-binding around the COND,
108 ;;; it could not be byte-compiled, because there would be an "unbind" 109 ;; it could not be byte-compiled, because there would be an "unbind"
109 ;;; byte-op between the final "call" and "return." Adding a 110 ;; byte-op between the final "call" and "return." Adding a
110 ;;; Bunbind_all byteop would fix this. 111 ;; Bunbind_all byteop would fix this.
111 ;;; 112 ;;
112 ;;; (defun foo (x y z) ... (foo a b c)) 113 ;; (defun foo (x y z) ... (foo a b c))
113 ;;; ... (const foo) (varref a) (varref b) (varref c) (call 3) END: (return) 114 ;; ... (const foo) (varref a) (varref b) (varref c) (call 3) END: (return)
114 ;;; ... (varref a) (varbind x) (varref b) (varbind y) (varref c) (varbind z) (goto 0) END: (unbind-all) (return) 115 ;; ... (varref a) (varbind x) (varref b) (varbind y) (varref c) (varbind z) (goto 0) END: (unbind-all) (return)
115 ;;; ... (varref a) (varset x) (varref b) (varset y) (varref c) (varset z) (goto 0) END: (return) 116 ;; ... (varref a) (varset x) (varref b) (varset y) (varref c) (varset z) (goto 0) END: (return)
116 ;;; 117 ;;
117 ;;; this also can be considered tail recursion: 118 ;; this also can be considered tail recursion:
118 ;;; 119 ;;
119 ;;; ... (const foo) (varref a) (call 1) (goto X) ... X: (return) 120 ;; ... (const foo) (varref a) (call 1) (goto X) ... X: (return)
120 ;;; could generalize this by doing the optimization 121 ;; could generalize this by doing the optimization
121 ;;; (goto X) ... X: (return) --> (return) 122 ;; (goto X) ... X: (return) --> (return)
122 ;;; 123 ;;
123 ;;; But this doesn't solve all of the problems: although by doing tail- 124 ;; But this doesn't solve all of the problems: although by doing tail-
124 ;;; recursion elimination in this way, the call-stack does not grow, the 125 ;; recursion elimination in this way, the call-stack does not grow, the
125 ;;; binding-stack would grow with each recursive step, and would eventually 126 ;; binding-stack would grow with each recursive step, and would eventually
126 ;;; overflow. I don't believe there is any way around this without lexical 127 ;; overflow. I don't believe there is any way around this without lexical
127 ;;; scope. 128 ;; scope.
128 ;;; 129 ;;
129 ;;; Wouldn't it be nice if Emacs Lisp had lexical scope. 130 ;; Wouldn't it be nice if Emacs Lisp had lexical scope.
130 ;;; 131 ;;
131 ;;; Idea: the form (lexical-scope) in a file means that the file may be 132 ;; Idea: the form (lexical-scope) in a file means that the file may be
132 ;;; compiled lexically. This proclamation is file-local. Then, within 133 ;; compiled lexically. This proclamation is file-local. Then, within
133 ;;; that file, "let" would establish lexical bindings, and "let-dynamic" 134 ;; that file, "let" would establish lexical bindings, and "let-dynamic"
134 ;;; would do things the old way. (Or we could use CL "declare" forms.) 135 ;; would do things the old way. (Or we could use CL "declare" forms.)
135 ;;; We'd have to notice defvars and defconsts, since those variables should 136 ;; We'd have to notice defvars and defconsts, since those variables should
136 ;;; always be dynamic, and attempting to do a lexical binding of them 137 ;; always be dynamic, and attempting to do a lexical binding of them
137 ;;; should simply do a dynamic binding instead. 138 ;; should simply do a dynamic binding instead.
138 ;;; But! We need to know about variables that were not necessarily defvarred 139 ;; But! We need to know about variables that were not necessarily defvarred
139 ;;; in the file being compiled (doing a boundp check isn't good enough.) 140 ;; in the file being compiled (doing a boundp check isn't good enough.)
140 ;;; Fdefvar() would have to be modified to add something to the plist. 141 ;; Fdefvar() would have to be modified to add something to the plist.
141 ;;; 142 ;;
142 ;;; A major disadvantage of this scheme is that the interpreter and compiler 143 ;; A major disadvantage of this scheme is that the interpreter and compiler
143 ;;; would have different semantics for files compiled with (dynamic-scope). 144 ;; would have different semantics for files compiled with (dynamic-scope).
144 ;;; Since this would be a file-local optimization, there would be no way to 145 ;; Since this would be a file-local optimization, there would be no way to
145 ;;; modify the interpreter to obey this (unless the loader was hacked 146 ;; modify the interpreter to obey this (unless the loader was hacked
146 ;;; in some grody way, but that's a really bad idea.) 147 ;; in some grody way, but that's a really bad idea.)
147 148
148 ;; Other things to consider: 149 ;; Other things to consider:
149 150
150 ;;;;; Associative math should recognize subcalls to identical function: 151 ;;;;; Associative math should recognize subcalls to identical function:
151 ;;;(disassemble (lambda (x) (+ (+ (foo) 1) (+ (bar) 2)))) 152 ;;;(disassemble (lambda (x) (+ (+ (foo) 1) (+ (bar) 2))))