0.6.11.40:
[sbcl.git] / src / compiler / eval-comp.lisp
1 ;;;; This file represents the current state of on-going development on
2 ;;;; compiler hooks for an interpreter that takes the compiler's IR1 of
3 ;;;; a program.
4
5 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; more information.
7 ;;;;
8 ;;;; This software is derived from the CMU CL system, which was
9 ;;;; written at Carnegie Mellon University and released into the
10 ;;;; public domain. The software is in the public domain and is
11 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
12 ;;;; files for more information.
13
14 (in-package "SB!C")
15
16 ;;; FIXME: Doesn't this belong somewhere else, like early-c.lisp?
17 (declaim (special *constants* *free-variables* *component-being-compiled*
18                   *code-vector* *next-location* *result-fixups*
19                   *free-functions* *source-paths* *failed-optimizations*
20                   *seen-blocks* *seen-functions* *list-conflicts-table*
21                   *continuation-number* *continuation-numbers*
22                   *number-continuations* *tn-id* *tn-ids* *id-tns*
23                   *label-ids* *label-id* *id-labels*
24                   *compiler-error-count* *compiler-warning-count*
25                   *compiler-style-warning-count* *compiler-note-count*
26                   *compiler-error-bailout*
27                   #!+sb-show *compiler-trace-output*
28                   *last-source-context* *last-original-source*
29                   *last-source-form* *last-format-string* *last-format-args*
30                   *last-message-count* *check-consistency*
31                   *all-components* *converting-for-interpreter*
32                   *source-info* *block-compile* *current-path*
33                   *current-component* *lexenv*))
34 \f
35 ;;; Translate form into the compiler's IR1 and perform environment
36 ;;; analysis. This is sort of a combination of COMPILE-FILE,
37 ;;; SUB-COMPILE-FILE, COMPILE-TOP-LEVEL, and COMPILE-COMPONENT.
38 (defun compile-for-eval (form)
39   (with-ir1-namespace
40     (let* ((*block-compile* nil)
41            (*lexenv* (make-null-lexenv))
42            (*compiler-error-bailout*
43             #'(lambda () (error "fatal error, aborting evaluation")))
44            (*current-path* nil)
45            (*last-source-context* nil)
46            (*last-original-source* nil)
47            (*last-source-form* nil)
48            (*last-format-string* nil)
49            (*last-format-args* nil)
50            (*last-message-count* 0)
51            ;; These are now bound by WITH-COMPILATION-UNIT. -- WHN 20000308
52            #+nil (*compiler-error-count* 0)
53            #+nil (*compiler-warning-count* 0)
54            #+nil (*compiler-style-warning-count* 0)
55            #+nil (*compiler-note-count* 0)
56            (*source-info* (make-lisp-source-info form))
57            (*converting-for-interpreter* t)
58            (*gensym-counter* 0)
59            (*warnings-p* nil)
60            (*failure-p* nil))
61
62       (clear-stuff nil)
63       (find-source-paths form 0)
64       ;; This LET comes from COMPILE-TOP-LEVEL.
65       ;; The noted DOLIST is a splice from a call that COMPILE-TOP-LEVEL makes.
66       (sb!xc:with-compilation-unit ()
67         (let ((lambdas (list (ir1-top-level form
68                                             '(original-source-start 0 0)
69                                             t))))
70           (declare (list lambdas))
71           (dolist (lambda lambdas)
72             (let* ((component
73                     (block-component (node-block (lambda-bind lambda))))
74                    (*all-components* (list component)))
75               (local-call-analyze component)))
76           (multiple-value-bind (components top-components)
77               (find-initial-dfo lambdas)
78             (let ((*all-components* (append components top-components)))
79               (when *check-consistency*
80                 (check-ir1-consistency *all-components*))
81               ;; This DOLIST body comes from the beginning of
82               ;; COMPILE-COMPONENT.
83               (dolist (component *all-components*)
84                 (ir1-finalize component)
85                 (let ((*component-being-compiled* component))
86                   (environment-analyze component))
87                 (annotate-component-for-eval component))
88             (when *check-consistency*
89               (check-ir1-consistency *all-components*))))
90           (car lambdas))))))
91 \f
92 ;;;; annotating IR1 for interpretation
93
94 (defstruct (lambda-eval-info (:constructor make-lambda-eval-info
95                                            (frame-size args-passed entries))
96                              (:copier nil))
97   frame-size            ; number of stack locations needed to hold locals
98   args-passed           ; number of referenced arguments passed to lambda
99   entries               ; a-list mapping entry nodes to stack locations
100   (function nil))       ; a function object corresponding to this lambda
101 (def!method print-object ((obj lambda-eval-info) str)
102   (print-unreadable-object (obj str :type t)))
103
104 (defstruct (entry-node-info (:constructor make-entry-node-info
105                                           (st-top nlx-tag))
106                             (:copier nil))
107   st-top        ; stack top when we encounter the entry node
108   nlx-tag)      ; tag to which to throw to get back entry node's context
109 (def!method print-object ((obj entry-node-info) str)
110   (print-unreadable-object (obj str :type t)))
111
112 ;;; Some compiler funny functions have definitions, so the interpreter can
113 ;;; call them. These require special action to coordinate the interpreter,
114 ;;; system call stack, and the environment. The annotation prepass marks the
115 ;;; references to these as :unused, so the interpreter doesn't try to fetch
116 ;;; functions through these undefined symbols.
117 (defconstant undefined-funny-funs
118   '(%special-bind %special-unbind %more-arg-context %unknown-values %catch
119     %unwind-protect %catch-breakup %unwind-protect-breakup
120     %lexical-exit-breakup %continue-unwind %nlx-entry))
121
122 ;;; Some kinds of functions are only passed as arguments to funny functions,
123 ;;; and are never actually evaluated at run time.
124 (defconstant non-closed-function-kinds '(:cleanup :escape))
125
126 ;;; This annotates continuations, lambda-vars, and lambdas. For each
127 ;;; continuation, we cache how its destination uses its value. This only buys
128 ;;; efficiency when the code executes more than once, but the overhead of this
129 ;;; part of the prepass for code executed only once should be negligible.
130 ;;;
131 ;;; As a special case to aid interpreting local function calls, we sometimes
132 ;;; note the continuation as :unused. This occurs when there is a local call,
133 ;;; and there is no actual function object to call; we mark the continuation as
134 ;;; :unused since there is nothing to push on the interpreter's stack.
135 ;;; Normally we would see a reference to a function that we would push on the
136 ;;; stack to later pop and apply to the arguments on the stack. To determine
137 ;;; when we have a local call with no real function object, we look at the node
138 ;;; to see whether it is a reference with a destination that is a :local
139 ;;; combination whose function is the reference node's continuation.
140 ;;;
141 ;;; After checking for virtual local calls, we check for funny functions the
142 ;;; compiler refers to for calling to note certain operations. These functions
143 ;;; are undefined, and if the interpreter tried to reference the function cells
144 ;;; of these symbols, it would get an error. We mark the continuations
145 ;;; delivering the values of these references as :unused, so the reference
146 ;;; never takes place.
147 ;;;
148 ;;; For each lambda-var, including a lambda's vars and its let's vars, we note
149 ;;; the stack offset used to access and store that variable. Then we note the
150 ;;; lambda with the total number of variables, so we know how big its stack
151 ;;; frame is. Also in the lambda's info is the number of its arguments that it
152 ;;; actually references; the interpreter never pushes or pops an unreferenced
153 ;;; argument, so we can't just use LENGTH on LAMBDA-VARS to know how many args
154 ;;; the caller passed.
155 ;;;
156 ;;; For each entry node in a lambda, we associate in the lambda-eval-info the
157 ;;; entry node with a stack offset. Evaluation code stores the frame pointer
158 ;;; in this slot upon processing the entry node to aid stack cleanup and
159 ;;; correct frame manipulation when processing exit nodes.
160 (defun annotate-component-for-eval (component)
161   (do-blocks (b component)
162     (do-nodes (node cont b)
163       (let* ((dest (continuation-dest cont))
164              (refp (typep node 'ref))
165              (leaf (if refp (ref-leaf node))))
166         (setf (continuation-info cont)
167               (cond ((and refp dest (typep dest 'basic-combination)
168                           (eq (basic-combination-kind dest) :local)
169                           (eq (basic-combination-fun dest) cont))
170                      :unused)
171                     ((and leaf (typep leaf 'global-var)
172                           (eq (global-var-kind leaf) :global-function)
173                           (member (sb!c::global-var-name leaf)
174                                   undefined-funny-funs
175                                   :test #'eq))
176                      :unused)
177                     ((and leaf (typep leaf 'clambda)
178                           (member (functional-kind leaf)
179                                   non-closed-function-kinds))
180                      (aver (not (eq (functional-kind leaf) :escape)))
181                      :unused)
182                     (t
183                      (typecase dest
184                        ;; Change locations in eval.lisp that think
185                        ;; :RETURN could occur.
186                        ((or mv-combination creturn exit) :multiple)
187                        (null :unused)
188                        (t :single))))))))
189   (dolist (lambda (component-lambdas component))
190     (let ((locals-count 0)
191           (args-passed-count 0))
192       (dolist (var (lambda-vars lambda))
193         (setf (leaf-info var) locals-count)
194         (incf locals-count)
195         (when (leaf-refs var) (incf args-passed-count)))
196       (dolist (let (lambda-lets lambda))
197         (dolist (var (lambda-vars let))
198           (setf (leaf-info var) locals-count)
199           (incf locals-count)))
200       (let ((entries nil))
201         (dolist (e (lambda-entries lambda))
202           (ecase (process-entry-node-p e)
203             (:blow-it-off)
204             (:local-lexical-exit
205              (push (cons e (make-entry-node-info locals-count nil))
206                    entries)
207              (incf locals-count))
208             (:non-local-lexical-exit
209              (push (cons e
210                          (make-entry-node-info locals-count
211                                                (incf locals-count)))
212                    entries)
213              (incf locals-count))))
214         (setf (lambda-info lambda)
215               (make-lambda-eval-info locals-count
216                                      args-passed-count
217                                      entries))))))
218
219 (defun process-entry-node-p (entry)
220   (let ((entry-cleanup (entry-cleanup entry)))
221     (dolist (nlx (environment-nlx-info (node-environment entry))
222                  :local-lexical-exit)
223       (let ((cleanup (nlx-info-cleanup nlx)))
224         (when (eq entry-cleanup cleanup)
225           (ecase (cleanup-kind cleanup)
226             ((:block :tagbody)
227              (return :non-local-lexical-exit))
228             ((:catch :unwind-protect)
229              (return :blow-it-off))))))))
230
231 ;;; Sometime consider annotations to exclude processing of exit nodes when
232 ;;; we want to do a tail-p thing.
233 \f
234 ;;;; defining funny functions for interpreter
235
236 #|
237 %listify-rest-args %more-arg %verify-argument-count %argument-count-error
238 %odd-key-arguments-error %unknown-key-argument-error
239 |#
240
241 (defun %verify-argument-count (supplied-args defined-args)
242   (unless (= supplied-args defined-args)
243     (error "Wrong argument count, wanted ~D and got ~D."
244            defined-args supplied-args))
245   (values))
246
247 ;;; Use (SETF SYMBOL-FUNCTION) instead of DEFUN so that the compiler
248 ;;; doesn't try to compile the hidden %THROW MV-CALL in the throw below as
249 ;;; a local recursive call.
250 (setf (symbol-function '%throw)
251       #'(lambda (tag &rest args)
252           (throw tag (values-list args))))
253
254 (defun %more-arg (args index)
255   (nth index args))
256
257 (defun %listify-rest-args (ptr count)
258   (declare (ignore count))
259   ptr)
260
261 (defun %more-arg-values (args start count)
262   (values-list (subseq args start count)))
263
264 (defun %argument-count-error (args-passed-count)
265   (error 'simple-program-error
266          :format-control "wrong number of arguments passed: ~S"
267          :format-arguments (list args-passed-count)))
268
269 (defun %odd-key-arguments-error ()
270   (error 'simple-program-error
271          :format-control "function called with odd number of &KEY arguments"
272          :format-arguments nil))
273
274 (defun %unknown-key-argument-error (key-arg-name)
275   (error 'simple-program-error
276          :format-control "unknown &KEY argument: ~S"
277          :format-arguments (list key-arg-name)))
278
279 (defun %cleanup-point ())
280
281 (defun value-cell-ref (x) (value-cell-ref x))