Declare COERCE and two helpers as EXPLICIT-CHECK.
[sbcl.git] / src / compiler / fopcompile.lisp
blobe117ba463740cd3ab235f9bf5ff124600edb9258
1 ;;;; A compiler from simple top-level forms to FASL operations.
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB!C")
14 ;;; SBCL has no proper byte compiler (having ditched the rather
15 ;;; ambitious and slightly flaky byte compiler inherited from CMU CL)
16 ;;; but its FOPs are a sort of byte code which is expressive enough
17 ;;; that we can compile some simple toplevel forms directly to them,
18 ;;; including very common operations like the forms that DEFVARs and
19 ;;; DECLAIMs macroexpand into.
20 ;;;
21 ;;; FIXME: The expexnasion problem.
22 ;;; FOPCOMPILE and FOPCOMPILABLE-P cause multiple expansion of macros,
23 ;;; which may be problematic with side-effecting macros. When
24 ;;; FOPCOMPILABLE-P succeeds, FOPCOMPILE is called, resulting in
25 ;;; double macroexpansion. When FOPCOMPILABLE-P fails,
26 ;;; IR1-CONVERT-FUNCTOID expands already expanded macros for a second
27 ;;; time.
28 ;;; And an edge case, when the top-level call has a complier-macro
29 ;;; which returns &whole it gets expanded three times, two times by
30 ;;; FOPCOMPILABLE-P and FOPCOMPILE, and one time by
31 ;;; PROCESS-TOPLEVEL-FORM, because unlike other macros, the expanded
32 ;;; form is still a macro-form. That's what the EXPAND optional
33 ;;; parameter solves, PROCESS-TOPLEVEL-FORM passes NIL, expanding
34 ;;; compiler macros at most once.
35 ;;; The instances of double expansion still remain, e.g. (fun (macro)),
36 ;;; since PROCESS-TOPLEVEL-FORM only expands the macros at the first
37 ;;; position.
39 (flet ((setq-fopcompilable-p (args)
40 (loop for (name value) on args by #'cddr
41 always (and (symbolp name)
42 (member (info :variable :kind name)
43 '(:special :global))
44 (fopcompilable-p value))))
45 (cold-svset-fopcompilable-p (args)
46 (destructuring-bind (thing index value) args
47 (and (symbolp thing)
48 (integerp index)
49 (eq (info :variable :kind thing) :global)
50 (typep value '(cons (eql function) (cons symbol null)))))))
51 (defun fopcompilable-p (form &optional (expand t))
52 ;; We'd like to be able to handle
53 ;; -- simple funcalls, nested recursively, e.g.
54 ;; (SET '*PACKAGE* (FIND-PACKAGE "CL-USER"))
55 ;; -- common self-evaluating forms like strings and keywords and
56 ;; fixnums, which are important for terminating
57 ;; the recursion of the simple funcalls above
58 ;; -- quoted lists (which are important for PROCLAIMs, which are
59 ;; common toplevel forms)
60 ;; -- fopcompilable stuff wrapped around non-fopcompilable expressions,
61 ;; e.g.
62 ;; (%DEFUN 'FOO (LAMBDA () ...) ...)
63 ;; -- the IF special form, to support things like (DEFVAR *X* 0)
64 ;; expanding into (UNLESS (BOUNDP '*X*) (SET '*X* 0))
66 ;; Special forms which we don't currently handle, but might consider
67 ;; supporting in the future are LOCALLY (with declarations),
68 ;; MACROLET, SYMBOL-MACROLET and THE.
69 ;; Also, if (FLET ((F () ...)) (DEFUN A () ...) (DEFUN B () ...))
70 ;; were handled, then it would probably automatically work in
71 ;; the cold loader too, providing definitions for A and B before
72 ;; executing all other toplevel forms.
73 #+sb-xc-host
74 (and expand
75 (or (and (self-evaluating-p form)
76 (constant-fopcompilable-p form))
77 (and (listp form)
78 (let ((function (car form)))
79 ;; It is assumed that uses of recognized functions are
80 ;; carefully controlled, and recursion on fopcompilable-p
81 ;; would say "yes".
82 (or (member function '(sb!impl::%defun
83 sb!impl::%defsetf
84 sb!kernel::%defstruct))
85 (and (symbolp function) ; no ((lambda ...) ...)
86 (get-properties (symbol-plist function)
87 '(:sb-cold-funcall-handler/for-effect
88 :sb-cold-funcall-handler/for-value)))
89 (and (eq function 'setf)
90 (fopcompilable-p (%macroexpand form *lexenv*)))
91 (and (eq function 'sb!kernel:%svset)
92 (cold-svset-fopcompilable-p (cdr form)))
93 (and (eq function 'setq)
94 (setq-fopcompilable-p (cdr form))))))))
95 #-sb-xc-host
96 (flet ((expand (form)
97 (if expand
98 (%macroexpand form *lexenv*)
99 (values form nil)))
100 (expand-cm (form)
101 (if expand
102 (expand-compiler-macro form)
103 (values form nil))))
104 (or (and (self-evaluating-p form)
105 (constant-fopcompilable-p form))
106 (and (symbolp form)
107 (multiple-value-bind (macroexpansion macroexpanded-p)
108 (expand form)
109 (if macroexpanded-p
110 (fopcompilable-p macroexpansion)
111 ;; Punt on :ALIEN variables
112 (let ((kind (info :variable :kind form)))
113 (member kind '(:special :constant :global :unknown))))))
114 (and (listp form)
115 (ignore-errors (list-length form))
116 (let ((macroexpansion (expand-cm form)))
117 (if (neq macroexpansion form)
118 (return-from fopcompilable-p (fopcompilable-p macroexpansion))
120 (multiple-value-bind (macroexpansion macroexpanded-p)
121 (expand form)
122 (if macroexpanded-p
123 (fopcompilable-p macroexpansion)
124 (destructuring-bind (operator &rest args) form
125 (case operator
126 ;; Special operators that we know how to cope with
127 ((progn)
128 (every #'fopcompilable-p args))
129 ((quote)
130 (and (= (length args) 1)
131 (constant-fopcompilable-p (car args))))
132 ((function)
133 (and (= (length args) 1)
134 ;; #'(LAMBDA ...), #'(NAMED-LAMBDA ...), etc. These
135 ;; are not fopcompileable as such, but we can compile
136 ;; the lambdas with the real compiler, and the rest
137 ;; of the expression with the fop-compiler.
138 (or (and (lambda-form-p (car args))
139 ;; The lambda might be closing over some
140 ;; variable, punt. As a further improvement,
141 ;; we could analyze the lambda body to
142 ;; see whether it really closes over any
143 ;; variables. One place where even simple
144 ;; analysis would be useful are the PCL
145 ;; slot-definition type-check-functions
146 ;; -- JES, 2007-01-13
147 (notany (lambda (binding)
148 (lambda-var-p (cdr binding)))
149 (lexenv-vars *lexenv*)))
150 ;; #'FOO, #'(SETF FOO), etc
151 (legal-fun-name-p (car args)))))
152 ((if)
153 (and (<= 2 (length args) 3)
154 (every #'fopcompilable-p args)))
155 ;; Allow SETQ only on special or global variables
156 ((setq)
157 (setq-fopcompilable-p args))
158 ;; The real toplevel form processing has already been
159 ;; done, so EVAL-WHEN handling will be easy.
160 ((eval-when)
161 (and (>= (length args) 1)
162 (eq (set-difference (car args)
163 '(:compile-toplevel
164 compile
165 :load-toplevel
166 load
167 :execute
168 eval))
169 nil)
170 (every #'fopcompilable-p (cdr args))))
171 ;; A LET or LET* that introduces only lexical
172 ;; bindings might be fopcompilable, depending on
173 ;; whether something closes over the bindings.
174 ;; (And whether there are declarations in the body,
175 ;; see below)
176 ((let let*)
177 (let-fopcompilable-p operator args))
178 ((locally)
179 (every #'fopcompilable-p args))
180 (otherwise
181 ;; ordinary function calls
182 (and (symbolp operator)
183 ;; If a LET/LOCALLY tries to introduce
184 ;; declarations, we'll detect it here, and
185 ;; disallow fopcompilation. This is safe,
186 ;; since defining a function/macro named
187 ;; DECLARE would violate a package lock.
188 (not (eq operator 'declare))
189 (not (special-operator-p operator))
190 (not (macro-function operator)) ; redundant check
191 ;; We can't FOP-FUNCALL with more than 255
192 ;; parameters. (We could theoretically use
193 ;; APPLY, but then we'd need to construct
194 ;; the parameter list for APPLY without
195 ;; calling LIST, which is probably more
196 ;; trouble than it's worth).
197 (<= (length args) 255)
198 (every #'fopcompilable-p args))))))))))))
200 (defun let-fopcompilable-p (operator args)
201 (when (>= (length args) 1)
202 (multiple-value-bind (body decls)
203 (parse-body (cdr args) :doc-string-allowed nil)
204 (declare (ignore body))
205 (let* ((orig-lexenv *lexenv*)
206 (*lexenv* (make-lexenv)))
207 ;; We need to check for declarations
208 ;; first. Otherwise the fake lexenv we're
209 ;; constructing might be invalid.
210 (and (null decls)
211 (loop for binding in (car args)
212 for name = (if (consp binding)
213 (first binding)
214 binding)
215 for value = (if (consp binding)
216 (second binding)
217 nil)
218 ;; Only allow binding locals, since special bindings can't
219 ;; be easily expressed with fops.
220 always (and (eq (info :variable :kind name)
221 :unknown)
222 (let ((*lexenv* (ecase operator
223 (let orig-lexenv)
224 (let* *lexenv*))))
225 (fopcompilable-p value)))
226 do (progn
227 (setf *lexenv* (make-lexenv))
228 (push (cons name
229 (make-lambda-var :%source-name name))
230 (lexenv-vars *lexenv*))))
231 (every #'fopcompilable-p (cdr args)))))))
233 (defun lambda-form-p (form)
234 (and (consp form)
235 (member (car form)
236 '(lambda named-lambda lambda-with-lexenv))))
238 ;;; Check that a literal form is fopcompilable. It would not be, for example,
239 ;;; when the form contains structures with funny MAKE-LOAD-FORMS.
240 (defun constant-fopcompilable-p (constant)
241 (let ((xset (alloc-xset)))
242 (labels ((grovel (value)
243 ;; Unless VALUE is an object which which obviously
244 ;; can't contain other objects
245 ;; FIXME: OAOOM. See MAYBE-EMIT-MAKE-LOAD-FORMS.
246 (unless (typep value
247 '(or #-sb-xc-host unboxed-array
248 symbol
249 number
250 character
251 string))
252 (if (xset-member-p value xset)
253 (return-from grovel nil)
254 (add-to-xset value xset))
255 (typecase value
256 (cons
257 (grovel (car value))
258 (grovel (cdr value)))
259 (simple-vector
260 (dotimes (i (length value))
261 (grovel (svref value i))))
262 ((vector t)
263 (dotimes (i (length value))
264 (grovel (aref value i))))
265 ((simple-array t)
266 ;; Even though the (ARRAY T) branch does the exact
267 ;; same thing as this branch we do this separately
268 ;; so that the compiler can use faster versions of
269 ;; array-total-size and row-major-aref.
270 (dotimes (i (array-total-size value))
271 (grovel (row-major-aref value i))))
272 ((array t)
273 (dotimes (i (array-total-size value))
274 (grovel (row-major-aref value i))))
275 ;; This is the same kludge as appears in EMIT-MAKE-LOAD-FORM
276 ;; which informs the xc that LAYOUTs are leaf-like nodes.
277 ;; This case was never reached before because cross-compiling
278 ;; used to generate target machine code for everything.
279 #+sb-xc-host (layout)
280 (instance
281 (multiple-value-bind (creation-form init-form)
282 (handler-case
283 (sb!xc:make-load-form value (make-null-lexenv))
284 (error (condition)
285 (compiler-error condition)))
286 (declare (ignore init-form))
287 (case creation-form
288 (:sb-just-dump-it-normally
289 ;; FIXME: Why is this needed? If the constant
290 ;; is deemed fopcompilable, then when we dump
291 ;; it we bind *dump-only-valid-structures* to
292 ;; NIL.
293 (fasl-validate-structure value *compile-object*)
294 ;; The above FIXME notwithstanding,
295 ;; there's never a need to grovel a layout.
296 (do-instance-tagged-slot (i value)
297 (grovel (%instance-ref value i))))
298 (:ignore-it)
300 (return-from constant-fopcompilable-p nil)))))
302 (return-from constant-fopcompilable-p nil))))))
303 (grovel constant))
306 ;;; FOR-VALUE-P is true if the value will be used (i.e., pushed onto
307 ;;; FOP stack), or NIL if any value will be discarded. FOPCOMPILABLE-P
308 ;;; has already ensured that the form can be fopcompiled.
310 ;;; See the expansion problem FIXME above fopcompilable-p.
311 (defun fopcompile (form path for-value-p &optional (expand t))
312 (let ((path (or (get-source-path form) (cons form path))))
313 (flet ((expand (form)
314 (if expand
315 (%macroexpand form *lexenv*)
316 (values form nil)))
317 (expand-cm (form)
318 (if expand
319 (expand-compiler-macro form)
320 (values form nil))))
321 (cond ((self-evaluating-p form)
322 (fopcompile-constant form for-value-p))
323 ((symbolp form)
324 (multiple-value-bind (macroexpansion macroexpanded-p)
325 (expand form)
326 (if macroexpanded-p
327 ;; Symbol macro
328 (fopcompile macroexpansion path for-value-p)
329 (let ((kind (info :variable :kind form)))
330 (cond
331 ((eq :special kind)
332 ;; Special variable
333 (fopcompile `(symbol-value ',form) path for-value-p))
335 ((member kind '(:global :constant))
336 ;; Global variable or constant.
337 (fopcompile `(symbol-global-value ',form) path for-value-p))
339 ;; Lexical
340 (let* ((lambda-var (cdr (assoc form (lexenv-vars *lexenv*))))
341 (handle (when lambda-var
342 (lambda-var-fop-value lambda-var))))
343 (cond (handle
344 (setf (lambda-var-ever-used lambda-var) t)
345 (when for-value-p
346 (sb!fasl::dump-push handle *compile-object*)))
348 ;; Undefined variable. Signal a warning, and
349 ;; treat it as a special variable reference, like
350 ;; the real compiler does -- do not elide even if
351 ;; the value is unused.
352 (note-undefined-reference form :variable)
353 (fopcompile `(symbol-value ',form)
354 path
355 for-value-p))))))))))
356 ((listp form)
357 (let ((macroexpansion (expand-cm form)))
358 (if (neq macroexpansion form)
359 ;; could expand into an atom, so start from the top
360 (return-from fopcompile
361 (fopcompile macroexpansion path for-value-p))))
362 (multiple-value-bind (macroexpansion macroexpanded-p)
363 (expand form)
364 (if macroexpanded-p
365 (fopcompile macroexpansion path for-value-p)
366 (destructuring-bind (operator &rest args) form
367 (case operator
368 ;; The QUOTE special operator is worth handling: very
369 ;; easy and very common at toplevel.
370 ((quote)
371 (fopcompile-constant (second form) for-value-p))
372 ;; A FUNCTION needs to be compiled properly, but doesn't
373 ;; need to prevent the fopcompilation of the whole form.
374 ;; We just compile it, and emit an instruction for pushing
375 ;; the function handle on the FOP stack.
376 ((function)
377 (fopcompile-function (second form) path for-value-p))
378 ;; KLUDGE! SB!C:SOURCE-LOCATION calls are normally handled
379 ;; by a compiler-macro. But if SPACE > DEBUG we choose not
380 ;; to record locations, which is strange because the main
381 ;; compiler does not have similar logic afaict.
382 ((source-location)
383 ;; FIXME: since the fopcompiler expands compiler-macros,
384 ;; this case should probably be killed. It can't execute.
385 (if (policy *policy* (and (> space 1)
386 (> space debug)))
387 (fopcompile-constant nil for-value-p)
388 (fopcompile (let ((*current-path* path))
389 (make-definition-source-location))
390 path
391 for-value-p)))
392 ((if)
393 (fopcompile-if args path for-value-p))
394 ((progn locally)
395 (if (and for-value-p (endp args))
396 (fopcompile nil path t)
397 (loop for (arg . next) on args
398 do (fopcompile arg
399 path (if next
401 for-value-p)))))
402 ((setq)
403 (if (and for-value-p (endp args))
404 (fopcompile nil path t)
405 (loop for (name value . next) on args by #'cddr
406 do (fopcompile `(set ',name ,value) path
407 (if next
409 for-value-p)))))
410 ((eval-when)
411 (destructuring-bind (situations &body body) args
412 (if (or (member :execute situations)
413 (member 'eval situations))
414 (fopcompile (cons 'progn body) path for-value-p)
415 (fopcompile nil path for-value-p))))
416 ((let let*)
417 (let ((orig-lexenv *lexenv*)
418 (*lexenv* (make-lexenv :default *lexenv*))
419 vars)
420 (loop for binding in (car args)
421 for name = (if (consp binding)
422 (first binding)
423 binding)
424 for value = (if (consp binding)
425 (second binding)
426 nil)
428 (let ((*lexenv* (if (eql operator 'let)
429 orig-lexenv
430 *lexenv*)))
431 (fopcompile value path t))
432 (let* ((obj (sb!fasl::dump-pop *compile-object*))
433 (var (make-lambda-var
434 :%source-name name
435 :fop-value obj)))
436 (push var vars)
437 (setf *lexenv*
438 (make-lexenv
439 :vars (list (cons name var))))))
440 (fopcompile (cons 'progn (cdr args)) path for-value-p)
441 (when (and vars
442 (and *source-info* path))
443 (let* ((tlf (source-path-tlf-number path))
444 (file-info (source-info-file-info *source-info*))
445 (*compiler-error-context*
446 (make-compiler-error-context
447 :original-source (stringify-form form)
448 :file-name (file-info-name file-info)
449 :file-position
450 (nth-value 1 (find-source-root tlf *source-info*))
451 :original-source-path (source-path-original-source path)
452 :lexenv *lexenv*)))
453 (note-unreferenced-vars vars *policy*)))))
454 ;; Otherwise it must be an ordinary funcall.
455 (otherwise
456 (cond
457 ;; Special hack: there's already a fop for
458 ;; find-undeleted-package-or-lose, so use it.
459 ;; (We could theoretically do the same for
460 ;; other operations, but I don't see any good
461 ;; candidates in a quick read-through of
462 ;; src/code/fop.lisp.)
463 ((and (eq operator
464 'sb!int:find-undeleted-package-or-lose)
465 (= 1 (length args))
466 for-value-p)
467 (fopcompile (first args) path t)
468 (sb!fasl::dump-fop 'sb!fasl::fop-package
469 *compile-object*))
471 (when (eq (info :function :where-from operator) :assumed)
472 (note-undefined-reference operator :function))
473 (fopcompile-constant operator t)
474 (dolist (arg args)
475 (fopcompile arg path t))
476 (if for-value-p
477 (sb!fasl::dump-fop 'sb!fasl::fop-funcall
478 *compile-object*)
479 (sb!fasl::dump-fop 'sb!fasl::fop-funcall-for-effect
480 *compile-object*))
481 (let ((n-args (length args)))
482 ;; stub: FOP-FUNCALL isn't going to be usable
483 ;; to compile more than this, since its count
484 ;; is a single byte. Maybe we should just punt
485 ;; to the ordinary compiler in that case?
486 (aver (<= n-args 255))
487 (sb!fasl::dump-byte n-args *compile-object*))))))))))
489 (bug "looks unFOPCOMPILEable: ~S" form))))))
491 (defun fopcompile-function (form path for-value-p)
492 (flet ((dump-fdefinition (name)
493 (fopcompile `(fdefinition ',name) path for-value-p)))
494 (if (consp form)
495 (cond
496 ;; Lambda forms are compiled with the real compiler
497 ((lambda-form-p form)
498 (let* ((handle (%compile form
499 *compile-object*
500 :path path)))
501 (when for-value-p
502 (sb!fasl::dump-push handle *compile-object*))))
503 ;; While function names are translated to a call to FDEFINITION.
504 ((legal-fun-name-p form)
505 (dump-fdefinition form))
507 (compiler-error "~S is not a legal function name." form)))
508 (dump-fdefinition form))))
510 (defun fopcompile-if (args path for-value-p)
511 (destructuring-bind (condition then &optional else)
512 args
513 (let ((else-label (incf *fopcompile-label-counter*))
514 (end-label (incf *fopcompile-label-counter*)))
515 (sb!fasl::dump-integer else-label *compile-object*)
516 (fopcompile condition path t)
517 ;; If condition was false, skip to the ELSE
518 (sb!fasl::dump-fop 'sb!fasl::fop-skip-if-false *compile-object*)
519 (fopcompile then path for-value-p)
520 ;; The THEN branch will have produced a value even if we were
521 ;; currently skipping to the ELSE branch (or over this whole
522 ;; IF). This is done to ensure that the stack effects are
523 ;; balanced properly when dealing with operations that are
524 ;; executed even when skipping over code. But this particular
525 ;; value will be bogus, so we drop it.
526 (when for-value-p
527 (sb!fasl::dump-fop 'sb!fasl::fop-drop-if-skipping *compile-object*))
528 ;; Now skip to the END
529 (sb!fasl::dump-integer end-label *compile-object*)
530 (sb!fasl::dump-fop 'sb!fasl::fop-skip *compile-object*)
531 ;; Start of the ELSE branch
532 (sb!fasl::dump-integer else-label *compile-object*)
533 (sb!fasl::dump-fop 'sb!fasl::fop-maybe-stop-skipping *compile-object*)
534 (fopcompile else path for-value-p)
535 ;; As before
536 (when for-value-p
537 (sb!fasl::dump-fop 'sb!fasl::fop-drop-if-skipping *compile-object*))
538 ;; End of IF
539 (sb!fasl::dump-integer end-label *compile-object*)
540 (sb!fasl::dump-fop 'sb!fasl::fop-maybe-stop-skipping *compile-object*)
541 ;; If we're still skipping, we must've triggered both of the
542 ;; drop-if-skipping fops. To keep the stack balanced, push a
543 ;; dummy value if needed.
544 (when for-value-p
545 (sb!fasl::dump-fop 'sb!fasl::fop-push-nil-if-skipping
546 *compile-object*)))))
548 (defun fopcompile-constant (form for-value-p)
549 (when for-value-p
550 ;; FIXME: Without this binding the dumper chokes on unvalidated
551 ;; structures: CONSTANT-FOPCOMPILABLE-P validates the structure
552 ;; about to be dumped, not its load-form. Compare and contrast
553 ;; with EMIT-MAKE-LOAD-FORM.
554 (let ((sb!fasl::*dump-only-valid-structures* nil))
555 (dump-object form *compile-object*))))
557 ;; Return CLASS if CREATION-FORM is `(allocate-instance (find-class ',CLASS))
558 (defun canonical-instance-maker-form-p (creation-form)
559 (let ((arg (and (typep creation-form
560 '(cons (eql allocate-instance) (cons t null)))
561 (cadr creation-form))))
562 (when (and arg (typep arg '(cons (eql find-class) (cons t null))))
563 (let ((class (cadr arg)))
564 (when (typep class '(cons (eql quote) (cons symbol null)))
565 (cadr class))))))
567 ;; If FORM can be implemented by FOP-ALLOCATE-INSTANCE,
568 ;; then fopcompile it and return a table index, otherwise return NIL.
569 (defun fopcompile-allocate-instance (form)
570 (let ((class-name (canonical-instance-maker-form-p form)))
571 (when class-name
572 (let ((file *compile-object*))
573 (dump-object class-name file)
574 (sb!fasl::dump-fop 'sb!fasl::fop-allocate-instance file)
575 (let ((index (sb!fasl::fasl-output-table-free file)))
576 (setf (sb!fasl::fasl-output-table-free file) (1+ index))
577 index)))))
579 ;; If FORM is one that we recognize as coming from MAKE-LOAD-FORM-SAVING-SLOTS,
580 ;; then return 3 values: the instance being affected, a slot name, and a value.
581 ;; Otherwise return three NILs.
582 (defun trivial-load-form-initform-args (form)
583 (multiple-value-bind (args const)
584 ;; these expressions suck, but here goes...
585 (cond ((typep form
586 '(cons
587 (eql setf)
588 (cons (cons (eql slot-value)
589 (cons instance
590 (cons (cons (eql quote) (cons symbol null))
591 null)))
592 (cons (cons (eql quote) (cons t null)) null))))
593 (values (cdadr form) (second (third form))))
594 ((typep form
595 '(cons
596 (eql slot-makunbound)
597 (cons instance
598 (cons (cons (eql quote) (cons symbol null)) null))))
599 ;; FIXME: could define SB-PCL:+SLOT-UNBOUND+ much earlier,
600 ;; and put the symbol in the kernel package or something.
601 (values (cdr form) 'sb!pcl::..slot-unbound..)))
602 (if args
603 (values (car args) (cadadr args) const)
604 (values nil nil nil))))
606 ;; If FORMS contains exactly one PROGN with an expected shape,
607 ;; then dump it using fops and return T. Otherwise return NIL.
608 (defun fopcompile-constant-init-forms (forms)
609 ;; It should be possible to extend this to allow FORMS to have
610 ;; any number of forms in the requisite shape.
611 (when (and (singleton-p forms)
612 (typep (car forms)
613 '(cons (eql progn) (satisfies list-length))))
614 (let ((forms (cdar forms))
615 (instance)
616 (slot-names)
617 (values))
618 (dolist (form forms
619 (let ((file *compile-object*))
620 (mapc (lambda (x) (dump-object x file)) (nreverse values))
621 (dump-object (cons (length slot-names) (nreverse slot-names))
622 file)
623 (dump-object instance file)
624 (sb!fasl::dump-fop 'sb!fasl::fop-initialize-instance file)
626 (multiple-value-bind (obj slot val)
627 (trivial-load-form-initform-args form)
628 (unless (if instance
629 (eq obj instance)
630 (typep (setq instance obj) 'instance))
631 (return nil))
632 ;; invoke recursive MAKE-LOAD-FORM stuff as necessary
633 (find-constant val)
634 (push slot slot-names)
635 (push val values))))))