1 ;;;; that part of DEFSTRUCT implementation which is needed not just
2 ;;;; in the target Lisp but also in the cross-compilation host
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
13 (in-package "SB!KERNEL")
15 (/show0
"code/defstruct.lisp 15")
19 ;;; Return the compiler layout for NAME. (The class referred to by
20 ;;; NAME must be a structure-like class.)
21 (defun compiler-layout-or-lose (name)
22 (let ((res (info :type
:compiler-layout name
)))
24 (error "Class is not yet defined or was undefined: ~S" name
))
25 ((not (typep (layout-info res
) 'defstruct-description
))
26 (error "Class is not a structure class: ~S" name
))
28 (sb!int
:check-deprecated-type name
)
31 (defun compiler-layout-ready-p (name)
32 (let ((layout (info :type
:compiler-layout name
)))
33 (and layout
(typep (layout-info layout
) 'defstruct-description
))))
35 (sb!xc
:defmacro %make-structure-instance-macro
(dd slot-specs
&rest slot-vars
)
36 (if (compiler-layout-ready-p (dd-name dd
))
37 `(truly-the ,(dd-name dd
)
38 (%make-structure-instance
,dd
,slot-specs
,@slot-vars
))
39 ;; Non-toplevel defstructs don't have a layout at compile time,
40 ;; so we need to construct the actual function at runtime -- but
41 ;; we cache it at the call site, so that we don't perform quite
43 `(let* ((cell (load-time-value (list nil
)))
46 (funcall fun
,@slot-vars
)
47 (funcall (setf (car cell
)
48 (%make-structure-instance-allocator
,dd
,slot-specs
))
51 (declaim (ftype (sfunction (defstruct-description list
) function
)
52 %make-structure-instance-allocator
))
53 (defun %make-structure-instance-allocator
(dd slot-specs
)
54 (let ((vars (make-gensym-list (length slot-specs
))))
57 (%make-structure-instance-macro
,dd
',slot-specs
,@vars
))))))
59 (defun %make-funcallable-structure-instance-allocator
(dd slot-specs
)
61 (bug "funcallable-structure-instance allocation with slots unimplemented"))
62 (let ((name (dd-name dd
))
63 (length (dd-length dd
))
64 (nobject (gensym "OBJECT")))
66 (compile nil
`(lambda ()
67 (let ((,nobject
(%make-funcallable-instance
,length
)))
68 (setf (%funcallable-instance-layout
,nobject
)
69 (%delayed-get-compiler-layout
,name
))
72 ;;; Delay looking for compiler-layout until the constructor is being
73 ;;; compiled, since it doesn't exist until after the EVAL-WHEN
74 ;;; (COMPILE) stuff is compiled. (Or, in the oddball case when
75 ;;; DEFSTRUCT is executing in a non-toplevel context, the
76 ;;; compiler-layout still doesn't exist at compilation time, and we
77 ;;; delay still further.)
78 (sb!xc
:defmacro %delayed-get-compiler-layout
(name)
79 (let ((layout (info :type
:compiler-layout name
)))
81 ;; ordinary case: When the DEFSTRUCT is at top level,
82 ;; then EVAL-WHEN (COMPILE) stuff will have set up the
83 ;; layout for us to use.
84 (unless (typep (layout-info layout
) 'defstruct-description
)
85 (error "Class is not a structure class: ~S" name
))
88 ;; KLUDGE: In the case that DEFSTRUCT is not at top-level
89 ;; the layout doesn't exist at compile time. In that case
90 ;; we laboriously look it up at run time. This code will
91 ;; run on every constructor call and will likely be quite
92 ;; slow, so if anyone cares about performance of
93 ;; non-toplevel DEFSTRUCTs, it should be rewritten to be
94 ;; cleverer. -- WHN 2002-10-23
96 "implementation limitation: ~
97 Non-toplevel DEFSTRUCT constructors are slow.")
98 (with-unique-names (layout)
99 `(let ((,layout
(info :type
:compiler-layout
',name
)))
100 (unless (typep (layout-info ,layout
) 'defstruct-description
)
101 (error "Class is not a structure class: ~S" ',name
))
104 ;;; re. %DELAYED-GET-COMPILER-LAYOUT and COMPILE-TIME-FIND-LAYOUT, above..
106 ;;; FIXME: Perhaps both should be defined with SB!XC:DEFMACRO?
107 ;;; FIXME: Do we really need both? If so, their names and implementations
108 ;;; should probably be tweaked to be more parallel.
110 ;;;; DEFSTRUCT-DESCRIPTION
112 ;;; The DEFSTRUCT-DESCRIPTION structure holds compile-time information
113 ;;; about a structure type.
114 ;;; Its definition occurs in 'early-classoid.lisp'
115 (defmethod print-object ((x defstruct-description
) stream
)
116 (print-unreadable-object (x stream
:type t
:identity t
)
117 (prin1 (dd-name x
) stream
)))
119 ;;; Does DD describe a structure with a class?
120 (defun dd-class-p (dd)
121 (if (member (dd-type dd
) '(structure funcallable-structure
)) t nil
))
123 (defun dd-layout-or-lose (dd)
124 (compiler-layout-or-lose (dd-name dd
)))
126 ;;;; DEFSTRUCT-SLOT-DESCRIPTION
128 ;;; A DEFSTRUCT-SLOT-DESCRIPTION holds compile-time information about
129 ;;; a structure slot. These objects are immutable.
130 (def!struct
(defstruct-slot-description
131 (:constructor make-dsd
(name type accessor-name bits default
))
134 #-sb-xc-host
(:pure t
))
135 (name nil
:read-only t
) ; name of slot
136 (type t
:read-only t
) ; declared type specifier
137 (accessor-name nil
:type symbol
:read-only t
) ; name of the accessor function
138 ;; Packed integer with 4 subfields.
139 ;; FIXNUM is ok for the host - it's guaranteed to be at least 16 signed bits
140 ;; and we don't have structures whose slot indices run into the thousands.
141 (bits 0 :type fixnum
:read-only t
)
142 (default nil
:read-only t
)) ; default value expression
143 #!-sb-fluid
(declaim (freeze-type defstruct-slot-description
))
145 (eval-when (:compile-toplevel
)
146 ;; Ensure that rsd-index is representable in 3 bits. (Can easily be changed)
147 (assert (<= (1+ (length *raw-slot-data
*)) 8)))
149 ;; genesis needs to know how many bits are to the right of the 'index' field
150 ;; in the packed BITS slot of a DSD.
151 (defconstant +dsd-index-shift
+ 6)
152 (defun pack-dsd-bits (index read-only safe-p always-boundp rsd-index
)
153 (logior (ash index
+dsd-index-shift
+)
154 (if read-only
(ash 1 5) 0)
155 (if safe-p
(ash 1 4) 0)
156 (if always-boundp
(ash 1 3) 0)
157 (the (unsigned-byte 3) (if rsd-index
(1+ rsd-index
) 0))))
159 (declaim (inline dsd-always-boundp
161 ; dsd-read-only ; compilation order problem
165 ;;; In general we type-check a slot when it is written, not when read.
166 ;;; There are cases where we must check each read though:
168 ;;; (1) a structure subtype can constrain a slot type more highly than the
169 ;;; parent type constrains it. This requires that each read via the subtype's
170 ;;; accessor be type-checked, because a write via the parent writer may
171 ;;; store a value that does not satisfy the more restrictive constraint.
172 ;;; These slots have SAFE-P = 0 in the dsd.
173 ;;; (2) If a BOA constructor leaves an ordinary (non-raw) slot uninitialized,
174 ;;; then the slot contains the unbound-marker which can be tested with just
175 ;;; an EQ comparison. Such slots have ALWAYS-BOUNDP = 0 in the dsd.
176 ;;; This does not apply to raw slots, which can not hold an unbound marker.
178 ;;; Note that inheritance in the presence of a BOA constructor can cause
179 ;;; the parent structure's notion of ALWAYS-BOUNDP to be wrong.
180 ;;; We don't try to deal with that.
181 ;;; FIXME: We could emit a style-warning if this happens, and/or if any code
182 ;;; was compiled under the assumption that the slot was safe.
184 ;;; Further note that MAKE-LOAD-FORM methods can do damage to type invariants
185 ;;; without any efficient means of detection, if MAKE-LOAD-FORM-SAVING-SLOTS
186 ;;; is used without specifying all slots.
188 ;; Index into *RAW-SLOT-DATA* vector of the RAW-SLOT-DATA for this slot.
189 ;; The index is -1 if this slot is not raw.
190 (defun dsd-rsd-index (dsd)
191 (let ((val (ldb (byte 3 0) (dsd-bits dsd
))))
192 (if (plusp val
) (1- val
))))
193 ;; Whether the slot is always bound. Slots are almost always bound,
194 ;; the exception being those which appear as an &AUX var with no value
195 ;; in a BOA constructor.
196 (defun dsd-always-boundp (dsd) (logbitp 3 (dsd-bits dsd
)))
197 ;; Whether the slot is known to be always of the specified type
198 ;; A slot may be SAFE-P even if not always-boundp.
199 (defun dsd-safe-p (dsd) (logbitp 4 (dsd-bits dsd
)))
200 (defun dsd-read-only (dsd) (logbitp 5 (dsd-bits dsd
)))
201 ;; its position in the implementation sequence
202 (defun dsd-index (dsd) (ash (dsd-bits dsd
) (- +dsd-index-shift
+)))
204 (!set-load-form-method defstruct-slot-description
(:host
:xc
:target
))
205 (defmethod print-object ((x defstruct-slot-description
) stream
)
206 (print-unreadable-object (x stream
:type t
)
207 (prin1 (dsd-name x
) stream
)))
208 (defun dsd-raw-slot-data (dsd)
209 (let ((rsd-index (dsd-rsd-index dsd
)))
211 (svref *raw-slot-data
* rsd-index
))))
212 (defun dsd-raw-type (dsd)
213 (acond ((dsd-raw-slot-data dsd
) (raw-slot-data-raw-type it
))
216 ;;;; typed (non-class) structures
218 ;;; Return a type specifier we can use for testing :TYPE'd structures.
219 (defun dd-lisp-type (defstruct)
220 (ecase (dd-type defstruct
)
222 (vector `(simple-array ,(dd-element-type defstruct
) (*)))))
224 ;;;; shared machinery for inline and out-of-line slot accessor functions
226 ;;; Classic comment preserved for entertainment value:
228 ;;; "A lie can travel halfway round the world while the truth is
229 ;;; putting on its shoes." -- Mark Twain
231 ;;;; the legendary DEFSTRUCT macro itself (both CL:DEFSTRUCT and its
232 ;;;; close personal friend SB!XC:DEFSTRUCT)
234 (sb!xc
:defmacro delay-defstruct-functions
(name &rest forms
)
235 ;; KLUDGE: If DEFSTRUCT is not at the top-level,
236 ;; (typep x 'name) and similar forms can't get optimized
237 ;; and produce style-warnings for unknown types.
238 (let ((forms (cons 'progn forms
)))
239 (if (compiler-layout-ready-p name
)
243 (defun %defstruct-package-locks
(dd)
244 (let ((name (dd-name dd
)))
245 #+sb-xc-host
(declare (ignore name
))
246 (with-single-package-locked-error
247 (:symbol name
"defining ~S as a structure"))
248 (awhen (dd-predicate-name dd
)
249 (with-single-package-locked-error
250 (:symbol it
"defining ~s as a predicate for ~s structure" name
)))
251 (awhen (dd-copier-name dd
)
252 (with-single-package-locked-error
253 (:symbol it
"defining ~s as a copier for ~s structure" name
)))
254 #-sb-xc-host
; does nothing anyway except warn about non-use of CTOR
255 (dolist (ctor (dd-constructors dd
))
256 (with-single-package-locked-error
257 (:symbol
(car ctor
) "defining ~s as a constructor for ~s structure" name
)))
258 (dolist (dsd (dd-slots dd
))
259 (awhen (dsd-accessor-name dsd
)
260 (with-single-package-locked-error
261 (:symbol it
"defining ~s as an accessor for ~s structure" name
))))))
263 ;;; Special var used by autogenerated print functions.
264 (sb!xc
:proclaim
'(special *current-level-in-print
*))
266 ;;; shared logic for host macroexpansion for SB!XC:DEFSTRUCT and
267 ;;; cross-compiler macroexpansion for CL:DEFSTRUCT
268 ;;; This monster has exactly one inline use in the final image,
269 ;;; and we can drop the definition.
270 (declaim (inline !expander-for-defstruct
))
271 (defun !expander-for-defstruct
(null-env-p name-and-options slot-descriptions
272 expanding-into-code-for
)
274 (((dd classoid inherits
)
275 (parse-defstruct null-env-p name-and-options slot-descriptions
))
276 (boa-constructors (member-if #'listp
(dd-constructors dd
) :key
#'cdr
))
277 (keyword-constructors (ldiff (dd-constructors dd
) boa-constructors
))
278 (constructor-definitions
280 (when keyword-constructors
281 (let ((primary (caar keyword-constructors
)))
283 `(defun ,primary
,@(structure-ctor-lambda-parts dd
:default
))
284 ;; Quasi-bogus: not all the right effects on globaldb
285 ;; happen by defining functions this cheating way.
286 (mapcar (lambda (other)
287 `(setf (fdefinition ',(car other
))
288 (fdefinition ',primary
)))
289 (rest keyword-constructors
)))))
290 (mapcar (lambda (ctor)
292 ,@(structure-ctor-lambda-parts dd
(cdr ctor
))))
296 (when (dd-print-option dd
)
297 (let* ((x (make-symbol "OBJECT"))
298 (s (make-symbol "STREAM"))
299 (fname (dd-printer-fname dd
))
300 (depthp (eq (dd-print-option dd
) :print-function
)))
301 ;; Giving empty :PRINT-OBJECT or :PRINT-FUNCTION options
302 ;; leaves FNAME eq to NIL. The user-level effect is
303 ;; to generate a PRINT-OBJECT method specialized for the type,
304 ;; implementing the default #S structure-printing behavior.
306 (setf fname
'default-structure-print depthp t
))
307 ((not (symbolp fname
))
308 ;; Don't dump the source form into the DD constant;
309 ;; just indicate that there was an expression there.
310 (setf (dd-printer-fname dd
) t
)))
311 `((defmethod print-object ((,x
,name
) ,s
)
312 (funcall #',fname
,x
,s
313 ,@(if depthp
`(*current-level-in-print
*)))))))))
314 ;; Return a list of forms and the DD-NAME.
317 `(,@(when (eq expanding-into-code-for
:target
)
318 ;; Note we intentionally enforce package locks, calling
319 ;; %DEFSTRUCT first. %DEFSTRUCT has the tests (and resulting
320 ;; CERROR) for collisions with LAYOUTs which already exist in
321 ;; the runtime. If there are collisions, we want the user's
322 ;; response to CERROR to control what happens. If the ABORT
323 ;; restart is chosen, %COMPILER-DEFSTRUCT should not modify
324 ;; the definition the class.
325 `((eval-when (:compile-toplevel
:load-toplevel
:execute
)
326 (%defstruct-package-locks
',dd
))))
327 (%defstruct
',dd
',inherits
(sb!c
:source-location
))
328 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
329 (%compiler-defstruct
',dd
',inherits
))
330 ,@(when (eq expanding-into-code-for
:target
)
331 `((delay-defstruct-functions
333 ,@(awhen (dd-copier-name dd
)
334 `((defun ,(dd-copier-name dd
) (instance)
335 (copy-structure (the ,(dd-name dd
) instance
)))))
336 ,@(awhen (dd-predicate-name dd
)
337 `((defun ,(dd-predicate-name dd
) (object)
338 (typep object
',(dd-name dd
)))))
339 ,@(accessor-definitions dd classoid
))
340 ;; This must be in the same lexical environment
341 ,@constructor-definitions
343 ;; Various other operations only make sense on the target SBCL.
344 (%target-defstruct
',dd
))))
346 ;; FIXME: missing package lock checks
347 `((eval-when (:compile-toplevel
:load-toplevel
:execute
)
348 (%proclaim-defstruct-ctors
',dd
)
349 (setf (info :typed-structure
:info
',name
) ',dd
))
350 (setf (info :source-location
:typed-structure
',name
)
351 (sb!c
:source-location
))
352 ,@(when (eq expanding-into-code-for
:target
)
353 `(,@(typed-accessor-definitions dd
)
354 ,@(typed-predicate-definitions dd
)
355 ,@(typed-copier-definitions dd
)
356 ,@constructor-definitions
358 `((setf (fdocumentation ',(dd-name dd
) 'structure
)
363 (sb!xc
:defmacro defstruct
(name-and-options &rest slot-descriptions
)
364 ;; All defstructs are toplevel in SBCL's own source code,
365 ;; so pass T for null-lexenv.
366 `(progn ,@(!expander-for-defstruct
367 t name-and-options slot-descriptions
:target
)))
370 (sb!xc
:defmacro defstruct
(name-and-options &rest slot-descriptions
372 "DEFSTRUCT {Name | (Name Option*)} [Documentation] {Slot | (Slot [Default] {Key Value}*)}
373 Define the structure type Name. Instances are created by MAKE-<name>,
374 which takes &KEY arguments allowing initial slot values to the specified.
375 A SETF'able function <name>-<slot> is defined for each slot to read and
376 write slot values. <name>-p is a type predicate.
378 Popular DEFSTRUCT options (see manual for others):
382 Specify the name for the constructor or predicate.
384 (:CONSTRUCTOR Name Lambda-List)
385 Specify the name and arguments for a BOA constructor
386 (which is more efficient when keyword syntax isn't necessary.)
388 (:INCLUDE Supertype Slot-Spec*)
389 Make this type a subtype of the structure type Supertype. The optional
390 Slot-Specs override inherited slot options.
395 Asserts that the value of this slot is always of the specified type.
398 If true, no setter function is defined for this slot."
399 (multiple-value-bind (forms name
)
400 (!expander-for-defstruct
402 (sb!kernel
:lexenv
(sb!c
::null-lexenv-p env
))
403 ;; a LOCALLY environment would be fine,
404 ;; but is not an important case to handle.
405 #!+sb-fasteval
(sb!interpreter
:basic-env nil
)
407 name-and-options slot-descriptions
:target
)
408 `(progn ,@forms
',name
)))
411 (defmacro sb
!xc
:defstruct
(name-and-options &rest slot-descriptions
)
412 "Cause information about a target structure to be built into the
414 `(progn ,@(!expander-for-defstruct
415 t name-and-options slot-descriptions
:host
)))
417 ;;;; functions to generate code for various parts of DEFSTRUCT definitions
419 ;;; First, a helper to determine whether a name names an inherited
421 (defun accessor-inherited-data (name defstruct
)
422 (assoc name
(dd-inherited-accessor-alist defstruct
) :test
#'eq
))
424 ;;; Return a list of forms which create a predicate function for a
426 (defun typed-predicate-definitions (defstruct)
427 (let ((name (dd-name defstruct
))
428 (predicate-name (dd-predicate-name defstruct
))
429 (argname 'x
)) ; KISS: no user code appears in the DEFUN
431 (aver (dd-named defstruct
))
432 (let ((ltype (dd-lisp-type defstruct
))
433 (name-index (cdr (car (last (find-name-indices defstruct
))))))
434 `((defun ,predicate-name
(,argname
)
435 (and (typep ,argname
',ltype
)
437 ((subtypep ltype
'list
)
438 `(do ((head (the ,ltype
,argname
) (cdr head
))
440 ((or (not (consp head
)) (= i
,name-index
))
441 (and (consp head
) (eq ',name
(car head
))))))
442 ((subtypep ltype
'vector
)
443 `(and (>= (length (the ,ltype
,argname
))
444 ,(dd-length defstruct
))
445 (eq ',name
(aref (the ,ltype
,argname
) ,name-index
))))
446 (t (bug "Unhandled representation type in typed DEFSTRUCT: ~
447 ~/sb!impl:print-type-specifier/."
450 ;;; Return a list of forms to create a copier function of a typed DEFSTRUCT.
451 (defun typed-copier-definitions (defstruct)
452 (when (dd-copier-name defstruct
)
453 `((setf (fdefinition ',(dd-copier-name defstruct
)) #'copy-seq
)
454 (declaim (ftype function
,(dd-copier-name defstruct
))))))
456 ;;; Return a list of function definitions for accessing and setting
457 ;;; the slots of a typed DEFSTRUCT. The functions are proclaimed to be
458 ;;; inline, and the types of their arguments and results are declared
459 ;;; as well. We count on the compiler to do clever things with ELT.
460 (defun typed-accessor-definitions (defstruct)
462 (let ((ltype (dd-lisp-type defstruct
)))
463 (dolist (slot (dd-slots defstruct
))
464 (let ((name (dsd-accessor-name slot
))
465 (index (dsd-index slot
))
467 (slot-type `(and ,(dsd-type slot
)
468 ,(dd-element-type defstruct
))))
469 (let ((inherited (accessor-inherited-data name defstruct
)))
472 (stuff `(declaim (inline ,name
,@(unless (dsd-read-only slot
)
474 (stuff `(defun ,name
(structure)
475 (declare (type ,ltype structure
))
476 (the ,slot-type
(elt structure
,index
))))
477 (unless (dsd-read-only slot
)
479 `(defun (setf ,name
) (,(car new-value
) structure
)
480 (declare (type ,ltype structure
) (type ,slot-type .
,new-value
))
481 (setf (elt structure
,index
) .
,new-value
)))))
482 ((not (= (cdr inherited
) index
))
483 (style-warn "~@<Non-overwritten accessor ~S does not access ~
484 slot with name ~S (accessing an inherited slot ~
485 instead).~:@>" name
(dsd-name slot
))))))))
491 ;;; A defstruct option can be either a keyword or a list of a keyword
492 ;;; and arguments for that keyword; specifying the keyword by itself is
493 ;;; equivalent to specifying a list consisting of the keyword
494 ;;; and no arguments.
495 ;;; It is unclear whether that is meant to imply that any of the keywords
496 ;;; may be present in their atom form, or only if the grammar at the top
497 ;;; shows the atom form does <atom> have the meaning of (<atom>).
498 ;;; At least one other implementation accepts :NAMED as a singleton list.
499 ;; We take a more rigid view that the depicted grammar is exhaustive.
501 (defconstant-eqx +dd-option-names
+
502 ;; Each keyword, except :CONSTRUCTOR which may appear more than once,
503 ;; and :NAMED which is trivial, and unambiguous if present more than
504 ;; once, though possibly worth a style-warning.
505 #(:include
; at least 1 argument
506 :initial-offset
; exactly 1 argument
507 :pure
; exactly 1 argument [nonstandard]
508 :type
; exactly 1 argument
509 :conc-name
; 0 or 1 arg
516 ;;; Parse a single DEFSTRUCT option and store the results in DD.
517 (defun parse-1-dd-option (option dd seen-options
)
518 (let* ((keyword (first option
))
519 (bit (position keyword
+dd-option-names
+))
522 (arg (if arg-p
(car args
)))
524 (declare (type (unsigned-byte 9) seen-options
)) ; mask over DD-OPTION-NAMES
526 (if (logbitp bit seen-options
)
527 (error "More than one ~S option is not allowed" keyword
)
528 (setf seen-options
(logior seen-options
(ash 1 bit
))))
529 (multiple-value-bind (syntax-group winp
)
530 (cond ; Perform checking per comment at +DD-OPTION-NAMES+.
531 ((= bit
0) (values 0 (and arg-p
(proper-list-p args
)))) ; >1 arg
532 ((< bit
4) (values 1 (and arg-p
(not (cdr args
))))) ; exactly 1
533 (t (values 2 (or (not args
) (singleton-p args
))))) ; 0 or 1
535 (if (proper-list-p option
)
536 (error "DEFSTRUCT option ~S ~[requires at least~;~
537 requires exactly~;accepts at most~] one argument" keyword syntax-group
)
538 (error "Invalid syntax in DEFSTRUCT option ~S" option
)))))
541 ;; unlike (:predicate) and (:copier) which mean "yes" if supplied
542 ;; without their argument, (:conc-name) and :conc-name mean no conc-name.
543 ;; Also note a subtle difference in :conc-name "" vs :conc-name NIL.
544 ;; The former re-interns each slot name into *PACKAGE* which might
545 ;; not be the same as using the given name directly as an accessor.
546 (setf (dd-conc-name dd
) (if arg
(string arg
))))
547 (:constructor
; takes 0 to 2 arguments.
548 (destructuring-bind (&optional
(cname (symbolicate "MAKE-" name
))
549 (lambda-list nil ll-supplied-p
)) args
552 ;; Implementations disagree on the meaning of
553 ;; (:CONSTRUCTOR NIL (A B C)).
554 ;; The choices seem to be: don't define a constructor,
555 ;; define a constructor named NIL, signal a user error,
556 ;; or crash the system itself. The spec implies
557 ;; the behavior that we have, but at least a
558 ;; style-warning seems appropriate.
560 (style-warn "~S does not define a constructor" option
)))
561 ((not ll-supplied-p
) :default
)
565 (declare (dynamic-extent x
))
566 (subseq x
0 ; remove trailing NILs
567 (1+ (position-if #'identity x
:from-end t
))))
570 :accept
(lambda-list-keyword-mask
571 '(&optional
&rest
&key
&allow-other-keys
&aux
))
573 (dd-constructors dd
) ; preserve order, just because
574 (nconc (dd-constructors dd
) (list (cons cname lambda-list
))))))
576 (setf (dd-copier-name dd
) (if arg-p arg
(symbolicate "COPY-" name
))))
578 (setf (dd-predicate-name dd
) (if arg-p arg
(symbolicate name
"-P"))))
580 (setf (dd-include dd
) args
))
581 ((:print-function
:print-object
)
582 (when (dd-print-option dd
)
583 (error "~S and ~S may not both be specified"
584 (dd-print-option dd
) keyword
))
585 (setf (dd-print-option dd
) keyword
(dd-printer-fname dd
) arg
))
587 (cond ((member arg
'(list vector
))
588 (setf (dd-type dd
) arg
(dd-element-type dd
) t
))
589 ((and (listp arg
) (eq (first arg
) 'vector
))
590 (destructuring-bind (elt-type) (cdr arg
)
591 (setf (dd-type dd
) 'vector
(dd-element-type dd
) elt-type
)))
593 (error "~S is a bad :TYPE for DEFSTRUCT." arg
))))
595 (error "The DEFSTRUCT option :NAMED takes no arguments."))
597 (setf (dd-offset dd
) arg
)) ; FIXME: disallow (:INITIAL-OFFSET NIL)
599 (setf (dd-pure dd
) arg
))
601 (error "unknown DEFSTRUCT option:~% ~S" option
)))
604 ;;; Parse OPTIONS into the given DD.
605 (defun parse-defstruct-options (options dd
)
606 (let ((seen-options 0)
608 (dolist (option options
)
609 (if (eq option
:named
)
610 (setf named-p t
(dd-named dd
) t
)
613 (cond ((consp option
) option
)
615 '(:conc-name
:constructor
:copier
:predicate
))
618 ;; FIXME: ugly message (defstruct (s :include) a)
619 ;; saying "unrecognized" when it means "bad syntax"
620 (error "unrecognized DEFSTRUCT option: ~S" option
)))
625 (error ":OFFSET can't be specified unless :TYPE is specified."))
626 #!-compact-instance-header
627 (unless (dd-include dd
)
628 ;; FIXME: It'd be cleaner to treat no-:INCLUDE as defaulting
629 ;; to :INCLUDE STRUCTURE-OBJECT, and then let the general-case
630 ;; (INCF (DD-LENGTH DD) (DD-LENGTH included-DD)) logic take
631 ;; care of this. (Except that the :TYPE VECTOR and :TYPE
632 ;; LIST cases, with their :NAMED and un-:NAMED flavors,
633 ;; make that messy, alas.)
634 (incf (dd-length dd
))))
636 ;; In case we are here, :TYPE is specified.
638 ;; CLHS - "The structure can be :named only if the type SYMBOL
639 ;; is a subtype of the supplied element-type."
640 (multiple-value-bind (winp certainp
)
641 (subtypep 'symbol
(dd-element-type dd
))
642 (when (and (not winp
) certainp
)
643 (error ":NAMED option is incompatible with element ~
644 type ~/sb!impl:print-type-specifier/"
645 (dd-element-type dd
))))
646 (when (dd-predicate-name dd
)
647 (error ":PREDICATE cannot be used with :TYPE ~
648 unless :NAMED is also specified.")))
649 (awhen (dd-print-option dd
)
650 (error ":TYPE option precludes specification of ~S option" it
))
652 (incf (dd-length dd
)))
653 (let ((offset (dd-offset dd
)))
654 (when offset
(incf (dd-length dd
) offset
)))))
656 (let ((name (dd-name dd
)))
657 (collect ((keyword-ctors) (boa-ctors))
658 (let (no-constructors)
659 (dolist (constructor (dd-constructors dd
))
660 (destructuring-bind (ctor-name . ll
) constructor
661 (cond ((not ctor-name
) (setq no-constructors t
))
662 ((eq ll
:default
) (keyword-ctors constructor
))
663 (t (boa-ctors constructor
)))))
664 ;; Remove (NIL) and sort so that BOA constructors are last.
665 (setf (dd-constructors dd
)
668 (when (or (keyword-ctors) (boa-ctors))
669 (error "(:CONSTRUCTOR NIL) combined with other :CONSTRUCTORs"))
671 (append (or (keyword-ctors)
673 `((,(symbolicate "MAKE-" name
) .
:default
))))
676 (flet ((option-present-p (bit-name)
677 (logbitp (position bit-name
+dd-option-names
+) seen-options
)))
678 (declare (inline option-present-p
))
679 (when (and (not (option-present-p :predicate
))
680 (or (dd-class-p dd
) named-p
))
681 (setf (dd-predicate-name dd
) (symbolicate name
"-P")))
682 (unless (option-present-p :conc-name
)
683 (setf (dd-conc-name dd
) (string (gensymify* name
"-"))))
684 (unless (option-present-p :copier
)
685 (setf (dd-copier-name dd
) (symbolicate "COPY-" name
)))))
688 ;;; Given name and options and slot descriptions (and possibly doc
689 ;;; string at the head of slot descriptions) return a DD holding that
691 (defun parse-defstruct (null-env-p name-and-options slot-descriptions
)
692 (binding* (((name options
)
693 (if (listp name-and-options
)
694 (values (car name-and-options
) (cdr name-and-options
))
695 (values name-and-options nil
)))
696 (dd (make-defstruct-description null-env-p name
))
697 (option-bits (parse-defstruct-options options dd
)))
698 (when (dd-include dd
)
699 (frob-dd-inclusion-stuff dd option-bits
))
700 (when (stringp (car slot-descriptions
))
701 (setf (dd-doc dd
) (pop slot-descriptions
)))
704 #+sb-xc-host
(!inherits-for-structure dd
)
706 (let ((super (compiler-layout-or-lose (or (first (dd-include dd
))
707 'structure-object
))))
708 (concatenate 'simple-vector
709 (layout-inherits super
) (vector super
)))))
712 (let* ((classoid (make-structure-classoid :name
(dd-name dd
)))
713 (layout (make-layout :classoid classoid
:inherits inherits
)))
714 (setf (layout-invalid layout
) nil
715 (classoid-layout classoid
) layout
)
717 ;; Bind *pending-defstruct-type* to this classoid, which fixes a problem
718 ;; when redefining a DEFTYPE which appeared to be a raw slot. e.g.
719 ;; (DEFTYPE X () 'SINGLE-FLOAT) and later (DEFSTRUCT X (A 0 :TYPE X)).
720 ;; This is probably undefined behavior, but at least we'll not crash.
721 ;; Also make self-referential definitions not signal PARSE-UNKNOWN-TYPE
722 ;; on slots whose :TYPE option allows an instance of itself
723 (flet ((parse-slots ()
724 (dolist (slot-description slot-descriptions
)
725 (parse-1-dsd dd slot-description
))))
728 (when (info :type
:kind name
)
729 ;; It could be buried anywhere in a complicated type expression.
730 ;; There's no way to clear selectively, so just flush the cache.
731 (values-specifier-type-cache-clear))
732 (let ((*pending-defstruct-type
* proto-classoid
))
735 (values dd proto-classoid inherits
))))
737 ;;;; stuff to parse slot descriptions
739 ;;; Parse a slot description for DEFSTRUCT, add it to the description
740 ;;; and return it. If supplied, INCLUDED-SLOT is used to get the default,
741 ;;; type, and read-only flag for the new slot.
742 (defun parse-1-dsd (defstruct spec
&optional included-slot
743 &aux accessor-name
(always-boundp t
) (safe-p t
)
745 #-sb-xc-host
(declare (muffle-conditions style-warning
))
746 (multiple-value-bind (name default default-p type type-p read-only ro-p
)
750 ((or null
(member :conc-name
:constructor
:copier
:predicate
:named
))
751 (warn "slot name of ~S indicates probable syntax error in DEFSTRUCT" spec
))
753 (style-warn "slot name of ~S indicates possible syntax error in DEFSTRUCT" spec
)))
757 (name &optional
(default nil default-p
)
758 &key
(type nil type-p
) (read-only nil ro-p
))
760 (when (dd-conc-name defstruct
)
761 ;; the warning here is useful, but in principle we cannot
762 ;; distinguish between legitimate and erroneous use of
763 ;; these names when :CONC-NAME is NIL. In the common
764 ;; case (CONC-NAME non-NIL), there are alternative ways
765 ;; of writing code with the same effect, so a full
766 ;; warning is justified.
768 ((member :conc-name
:constructor
:copier
:predicate
:include
769 :print-function
:print-object
:type
:initial-offset
:pure
)
770 (warn "slot name of ~S indicates probable syntax error in DEFSTRUCT" name
))))
771 (values name default default-p
772 (uncross type
) type-p
774 (t (error 'simple-program-error
775 :format-control
"in DEFSTRUCT, ~S is not a legal slot ~
777 :format-arguments
(list spec
))))
779 (when (find name
(dd-slots defstruct
) :test
#'string
= :key
#'dsd-name
)
780 (error 'simple-program-error
781 ;; Todo: indicate whether name is a duplicate in the directly
782 ;; specified slots vs. exists in the ancestor and so should
783 ;; be in the (:include ...) clause instead of where it is.
784 :format-control
"duplicate slot name ~S"
785 :format-arguments
(list name
)))
786 (setf accessor-name
(if (dd-conc-name defstruct
)
787 (symbolicate (dd-conc-name defstruct
) name
)
789 (let ((predicate-name (dd-predicate-name defstruct
)))
790 (when (eql accessor-name predicate-name
)
791 ;; Some adventurous soul has named a slot so that its accessor
792 ;; collides with the structure type predicate. ANSI doesn't
793 ;; specify what to do in this case. As of 2001-09-04, Martin
794 ;; Atzmueller reports that CLISP and Lispworks both give
795 ;; priority to the slot accessor, so that the predicate is
796 ;; overwritten. We might as well do the same (as well as
797 ;; signalling a warning).
799 "~@<The structure accessor name ~S is the same as the name of the ~
800 structure type predicate. ANSI doesn't specify what to do in ~
801 this case. We'll overwrite the type predicate with the slot ~
802 accessor, but you can't rely on this behavior, so it'd be wise to ~
803 remove the ambiguity in your code.~@:>"
805 (setf (dd-predicate-name defstruct
) nil
))
806 ;; FIXME: It would be good to check for name collisions here, but
809 ;;x(when (and (fboundp accessor-name)
810 ;;x (not (accessor-inherited-data accessor-name defstruct)))
811 ;;x (style-warn "redefining ~/sb-impl::print-symbol-with-prefix/ ~
812 ;; in DEFSTRUCT" accessor-name)))
813 ;; which was done until sbcl-0.8.11.18 or so, is wrong: it causes
814 ;; a warning at MACROEXPAND time, when instead the warning should
815 ;; occur not just because the code was constructed, but because it
816 ;; is actually compiled or loaded.
819 (when (and (not default-p
) included-slot
)
820 (setf default
(dsd-default included-slot
)))
822 (let ((inherited-type (if included-slot
(dsd-type included-slot
) t
)))
823 (setf type
(cond ((not type-p
) inherited-type
)
824 ((eq inherited-type t
) type
)
825 (t `(and ,inherited-type
,type
)))))
828 (setq read-only
(dsd-read-only included-slot
)))
829 ((and ro-p
(not read-only
) (dsd-read-only included-slot
))
830 (error "~@<The slot ~S is :READ-ONLY in superclass, and so must ~
831 be :READ-ONLY in subclass.~:@>"
833 (setf rsd-index
(dsd-rsd-index included-slot
)
834 safe-p
(dsd-safe-p included-slot
)
835 always-boundp
(dsd-always-boundp included-slot
)
836 index
(dsd-index included-slot
))
838 (not (equal type
(dsd-type included-slot
)))
839 (not (sb!xc
:subtypep
(dsd-type included-slot
) type
)))
842 ;; Compute the index of this DSD. First decide whether the slot is raw.
843 (setf rsd-index
(and (eq (dd-type defstruct
) 'structure
)
844 (structure-raw-slot-data-index type
)))
847 (let ((rsd (svref *raw-slot-data
* rsd-index
)))
848 ;; If slot requires alignment of 2, then ensure that
849 ;; it has an odd (i.e. doubleword aligned) index.
850 (when (and (eql (raw-slot-data-alignment rsd
) 2)
851 (evenp (dd-length defstruct
)))
852 (incf (dd-length defstruct
)))
853 (raw-slot-data-n-words rsd
))
855 (setf index
(dd-length defstruct
))
856 (incf (dd-length defstruct
) n-words
))))
858 ;; Check for existence of any BOA constructor that leaves the
859 ;; slot with an unspecified value, as when it's initialized
860 ;; by an &AUX binding with no value (CLHS 3.4.6)
861 (when (and always-boundp
862 (some (lambda (ctor &aux
(ll-parts (cdr ctor
)))
863 ;; Keyword constructors store :DEFAULT in the cdr of the cell.
864 ;; BOA constructors store the parsed lambda list.
865 (and (listp ll-parts
) ; = (llks req opt rest key aux)
866 (some (lambda (binding)
867 (and (or (atom binding
) (not (cdr binding
)))
868 (string= (if (atom binding
) binding
(car binding
))
871 (dd-constructors defstruct
)))
872 (setf always-boundp nil
))
873 (unless always-boundp
874 ;; FIXME: the :TYPE option should not preclude storing #<unbound>
875 ;; unless the storage is a specialized numeric vector.
876 (when (or rsd-index
(neq (dd-type defstruct
) 'structure
))
877 (setf always-boundp t safe-p nil
))) ; "demote" to unsafe.
879 (let ((dsd (make-dsd name type accessor-name
880 (pack-dsd-bits index read-only safe-p
881 always-boundp rsd-index
)
883 (setf (dd-slots defstruct
) (nconc (dd-slots defstruct
) (list dsd
)))
886 ;;; When a value of type TYPE is stored in a structure, should it be
887 ;;; stored in a raw slot? Return the index of the matching RAW-SLOT-DATA
888 ;;; if TYPE should be stored in a raw slot, or NIL if not.
889 (defun structure-raw-slot-data-index (type)
890 (multiple-value-bind (fixnum? fixnum-certain?
)
891 (sb!xc
:subtypep type
'fixnum
)
892 ;; (The extra test for FIXNUM-CERTAIN? here is intended for
893 ;; bootstrapping the system. In particular, in sbcl-0.6.2, we set up
894 ;; LAYOUT before FIXNUM is defined, and so could bogusly end up
895 ;; putting INDEX-typed values into raw slots if we didn't test
897 (if (or fixnum?
(not fixnum-certain?
))
899 (dotimes (i (length *raw-slot-data
*))
900 (let ((data (svref *raw-slot-data
* i
)))
901 (when (sb!xc
:subtypep type
(raw-slot-data-raw-type data
))
904 (defun typed-structure-info-or-lose (name)
905 (or (info :typed-structure
:info name
)
906 (error ":TYPE'd DEFSTRUCT ~S not found for inclusion." name
)))
908 ;;; Process any included slots pretty much like they were specified.
909 ;;; Also inherit various other attributes.
910 (defun frob-dd-inclusion-stuff (dd option-bits
)
911 (destructuring-bind (included-name &rest modified-slots
) (dd-include dd
)
912 (let* ((type (dd-type dd
))
915 (layout-info (compiler-layout-or-lose included-name
))
916 (typed-structure-info-or-lose included-name
))))
918 ;; checks on legality
919 (unless (and (eq type
(dd-type included-structure
))
920 (type= (specifier-type (dd-element-type included-structure
))
921 (specifier-type (dd-element-type dd
))))
922 (error ":TYPE option mismatch between structures ~S and ~S"
923 (dd-name dd
) included-name
))
924 (let ((included-classoid (find-classoid included-name nil
)))
925 (when included-classoid
926 ;; It's not particularly well-defined to :INCLUDE any of the
927 ;; CMU CL INSTANCE weirdosities like CONDITION or
928 ;; GENERIC-FUNCTION, and it's certainly not ANSI-compliant.
929 (let* ((included-layout (classoid-layout included-classoid
))
930 (included-dd (layout-info included-layout
)))
931 (when (dd-alternate-metaclass included-dd
)
932 (error "can't :INCLUDE class ~S (has alternate metaclass)"
935 ;; A few more sanity checks: every allegedly modified slot exists
936 ;; and no name appears more than once.
937 (flet ((included-slot-name (slot-desc)
938 (if (atom slot-desc
) slot-desc
(car slot-desc
))))
939 (mapl (lambda (slots &aux
(name (included-slot-name (car slots
))))
940 (unless (find name
(dd-slots included-structure
)
941 :test
#'string
= :key
#'dsd-name
)
942 (error 'simple-program-error
943 :format-control
"slot name ~S not present in included structure"
944 :format-arguments
(list name
)))
945 (when (find name
(cdr slots
)
946 :test
#'string
= :key
#'included-slot-name
)
947 (error 'simple-program-error
948 :format-control
"included slot name ~S specified more than once"
949 :format-arguments
(list name
))))
952 (incf (dd-length dd
) (dd-length included-structure
))
953 (when (dd-class-p dd
)
954 ;; FIXME: This POSITION call should be foldable without read-time eval
955 ;; since literals are immutable, and +DD-OPTION-NAMES+ was initialized
957 (unless (logbitp #.
(position :pure
+dd-option-names
+) option-bits
)
958 (setf (dd-pure dd
) (dd-pure included-structure
))))
960 (setf (dd-inherited-accessor-alist dd
)
961 (dd-inherited-accessor-alist included-structure
))
962 (dolist (included-slot (dd-slots included-structure
))
963 (let* ((included-name (dsd-name included-slot
))
964 (modified (or (find included-name modified-slots
965 :key
(lambda (x) (if (atom x
) x
(car x
)))
968 ;; We stash away an alist of accessors to parents' slots
969 ;; that have already been created to avoid conflicts later
970 ;; so that structures with :INCLUDE and :CONC-NAME (and
971 ;; other edge cases) can work as specified.
972 (when (dsd-accessor-name included-slot
)
973 ;; the "oldest" (i.e. highest up the tree of inheritance)
974 ;; will prevail, so don't push new ones on if they
976 (pushnew (cons (dsd-accessor-name included-slot
)
977 (dsd-index included-slot
))
978 (dd-inherited-accessor-alist dd
)
979 :test
#'eq
:key
#'car
))
980 (let ((new-slot (parse-1-dsd dd modified included-slot
)))
981 (when (and (dsd-safe-p included-slot
) (not (dsd-safe-p new-slot
)))
985 ;;;; various helper functions for setting up DEFSTRUCTs
987 ;;; This function is called at macroexpand time to compute the INHERITS
988 ;;; vector for a structure type definition.
989 ;;; The cross-compiler is allowed to magically compute LAYOUT-INHERITS.
990 (defun !inherits-for-structure
(info)
991 (declare (type defstruct-description info
))
992 (let* ((include (dd-include info
))
993 (superclass-opt (dd-alternate-metaclass info
))
996 (compiler-layout-or-lose (first include
))
997 (classoid-layout (find-classoid
998 (or (first superclass-opt
)
999 'structure-object
))))))
1000 (case (dd-name info
)
1002 ;; STREAM is an abstract class and you can't :include it,
1003 ;; so the inheritance has to be hardcoded.
1004 (concatenate 'simple-vector
1005 (layout-inherits super
)
1006 (vector super
(classoid-layout (find-classoid 'stream
)))))
1007 ((fd-stream) ; Similarly, FILE-STREAM is abstract
1008 (concatenate 'simple-vector
1009 (layout-inherits super
)
1011 (classoid-layout (find-classoid 'file-stream
)))))
1012 ((sb!impl
::string-input-stream
; etc
1013 sb
!impl
::string-output-stream
1014 sb
!impl
::fill-pointer-output-stream
)
1015 (concatenate 'simple-vector
1016 (layout-inherits super
)
1018 (classoid-layout (find-classoid 'string-stream
)))))
1019 (t (concatenate 'simple-vector
1020 (layout-inherits super
)
1023 ;;; Do miscellaneous (LOAD EVAL) time actions for the structure
1024 ;;; described by DD. Create the class and LAYOUT, checking for
1025 ;;; incompatible redefinition.
1026 (defun %defstruct
(dd inherits source-location
)
1027 (declare (type defstruct-description dd
))
1029 ;; We set up LAYOUTs even in the cross-compilation host.
1030 (multiple-value-bind (classoid layout old-layout
)
1031 (ensure-structure-class dd inherits
"current" "new")
1032 (cond ((not old-layout
)
1033 (unless (eq (classoid-layout classoid
) layout
)
1034 (register-layout layout
)))
1036 (%redefine-defstruct classoid old-layout layout
)
1037 (let ((old-dd (layout-info old-layout
)))
1038 (when (defstruct-description-p old-dd
)
1039 (dolist (slot (dd-slots old-dd
))
1040 (fmakunbound (dsd-accessor-name slot
))
1041 (unless (dsd-read-only slot
)
1042 (fmakunbound `(setf ,(dsd-accessor-name slot
)))))))
1043 (setq layout
(classoid-layout classoid
))))
1044 (setf (find-classoid (dd-name dd
)) classoid
)
1046 (when source-location
1047 (setf (layout-source-location layout
) source-location
))))
1050 ;;; Return a form accessing the writable place used for the slot
1051 ;;; described by DD and DSD in the INSTANCE (a form).
1052 (defun %accessor-place-form
(dd dsd instance
)
1053 (let (;; Compute REF even if not using it, as a sanity-check of DD-TYPE.
1054 (ref (ecase (dd-type dd
)
1055 (structure '%instance-ref
)
1058 (index (dsd-index dsd
))
1059 (rsd (dsd-raw-slot-data dsd
)))
1061 (list (raw-slot-data-accessor-name rsd
) instance index
))
1063 (list ref index instance
))
1065 (list ref instance index
)))))
1067 ;;; Return the transform of conceptual FUNCTION one of {:READ,:WRITE,:SETF}
1068 ;;; as applied to ARGS, given SLOT-KEY which is a cons of a DD and a DSD.
1069 ;;; Return NIL on failure.
1070 (defun slot-access-transform (function args slot-key
)
1071 (when (consp args
) ; need at least one arg
1072 (let* ((dd (car slot-key
))
1073 (dsd (cdr slot-key
))
1074 ;; optimistically compute PLACE before checking length of ARGS
1075 ;; because we expect success, and this unifies the three cases.
1076 ;; :SETF is like an invocation of the SETF macro - newval is
1077 ;; the second arg, but :WRITER is #'(SETF fn) - newval is first.
1079 (%accessor-place-form
1080 dd dsd
`(the ,(dd-name dd
)
1081 ,(car (if (eq function
:write
) (cdr args
) args
)))))
1082 (type-spec (dsd-type dsd
)))
1083 (if (eq function
:read
)
1084 (when (singleton-p args
)
1085 ;; There are 4 cases of {safe,unsafe} x {always-boundp,possibly-unbound}
1086 ;; If unsafe - which implies TYPE-SPEC other than type T - then we must
1087 ;; check the type on each read. Assuming that type-checks reject
1088 ;; the unbound-marker, then we needn't separately check for it.
1089 (cond ((not (dsd-safe-p dsd
))
1090 `(the ,type-spec
,place
))
1092 (unless (dsd-always-boundp dsd
)
1093 (setf place
`(the* ((not (satisfies sb
!vm
::unbound-marker-p
))
1094 :context
(:struct-read
,(dd-name dd
) .
,(dsd-name dsd
)))
1096 (if (eq type-spec t
) place
`(truly-the ,type-spec
,place
)))))
1097 (when (singleton-p (cdr args
))
1098 (let ((inverse (info :setf
:expander
(car place
))))
1099 (flet ((check (newval)
1100 (if (eq type-spec t
)
1102 `(the* (,type-spec
:context
1103 (:struct
,(dd-name dd
) .
,(dsd-name dsd
)))
1107 ;; Instance setters take newval last, which matches
1108 ;; the order in which a use of SETF has them.
1109 `(,inverse
,@(cdr place
) ,(check (second args
))))
1111 ;; The call to #'(SETF fn) had newval first.
1112 ;; We need to preserve L-to-R evaluation.
1113 (once-only ((new (first args
)))
1114 `(,inverse
,@(cdr place
) ,(check new
))))))))))))
1116 ;;; Return a LAMBDA form which can be used to set a slot
1117 (defun slot-setter-lambda-form (dd dsd
)
1118 `(lambda (newval instance
)
1119 (declare (optimize (debug 0)))
1120 ,(slot-access-transform :setf
'(instance newval
) (cons dd dsd
))))
1122 ;;; Blow away all the compiler info for the structure CLASS. Iterate
1123 ;;; over this type, clearing the compiler structure type info, and
1124 ;;; undefining all the associated functions. If SUBCLASSES-P, also do
1125 ;;; the same for subclasses. FIXME: maybe rename UNDEFINE-FUN-NAME to
1126 ;;; UNDECLARE-FUNCTION-NAME?
1127 (defun undeclare-structure (classoid subclasses-p
)
1128 (let ((info (layout-info (classoid-layout classoid
))))
1129 (when (defstruct-description-p info
)
1130 (let ((type (dd-name info
)))
1131 (clear-info :type
:compiler-layout type
)
1132 ;; FIXME: shouldn't this undeclare any constructors too?
1133 (undefine-fun-name (dd-copier-name info
))
1134 (undefine-fun-name (dd-predicate-name info
))
1135 (dolist (slot (dd-slots info
))
1136 (let ((fun (dsd-accessor-name slot
)))
1137 (unless (accessor-inherited-data fun info
)
1138 (undefine-fun-name fun
)
1139 (unless (dsd-read-only slot
)
1140 (undefine-fun-name `(setf ,fun
)))))))
1141 ;; Clear out the SPECIFIER-TYPE cache so that subsequent
1142 ;; references are unknown types.
1143 (values-specifier-type-cache-clear)))
1145 (let ((subclasses (classoid-subclasses classoid
)))
1148 (dohash ((classoid layout
)
1151 (declare (ignore layout
))
1152 (undeclare-structure classoid nil
)
1153 (subs (classoid-proper-name classoid
)))
1154 ;; Is it really necessary to warn about
1155 ;; undeclaring functions for subclasses?
1157 (warn "undeclaring functions for old subclasses ~
1159 (classoid-name classoid
)
1162 ;;; core compile-time setup of any class with a LAYOUT, used even by
1163 ;;; !DEFSTRUCT-WITH-ALTERNATE-METACLASS weirdosities
1164 (defun %compiler-set-up-layout
(dd
1166 ;; Several special cases
1167 ;; (STRUCTURE-OBJECT itself, and
1168 ;; structures with alternate
1169 ;; metaclasses) call this function
1170 ;; directly, and they're all at the
1171 ;; base of the instance class
1172 ;; structure, so this is a handy
1173 ;; default. (But note
1174 ;; FUNCALLABLE-STRUCTUREs need
1176 (inherits (vector (find-layout t
))))
1178 (multiple-value-bind (classoid layout old-layout
)
1179 (multiple-value-bind (clayout clayout-p
)
1180 (info :type
:compiler-layout
(dd-name dd
))
1181 (ensure-structure-class dd
1184 "The most recently compiled"
1186 "the most recently loaded"
1187 :compiler-layout clayout
))
1189 (undeclare-structure (layout-classoid old-layout
)
1190 (and (classoid-subclasses classoid
)
1191 (not (eq layout old-layout
))))
1192 (setf (layout-invalid layout
) nil
)
1193 ;; FIXME: it might be polite to hold onto old-layout and
1194 ;; restore it at the end of the file. -- RMK 2008-09-19
1195 ;; (International Talk Like a Pirate Day).
1196 (warn "~@<Clobbering the compiler's idea of the layout of ~A.~:@>"
1199 (unless (eq (classoid-layout classoid
) layout
)
1200 (register-layout layout
:invalidate nil
))
1201 (setf (find-classoid (dd-name dd
)) classoid
)))
1203 ;; At this point the class should be set up in the INFO database.
1204 ;; But the logic that enforces this is a little tangled and
1205 ;; scattered, so it's not obvious, so let's check.
1206 (aver (find-classoid (dd-name dd
) nil
))
1208 (setf (info :type
:compiler-layout
(dd-name dd
)) layout
))
1211 (defun %proclaim-defstruct-ctors
(dd)
1212 (dolist (ctor (dd-constructors dd
))
1213 (let ((ftype (%struct-ctor-ftype dd
(cdr ctor
) (dd-element-type dd
))))
1214 (sb!c
:proclaim-ftype
(car ctor
) dd ftype
:declared
))))
1216 ;;; Do (COMPILE LOAD EVAL)-time actions for the normal (not
1217 ;;; ALTERNATE-LAYOUT) DEFSTRUCT described by DD.
1218 ;;; This includes generation of a style-warning about previously compiled
1219 ;;; calls to the accessors and/or predicate that weren't inlined.
1220 (defun %compiler-defstruct
(dd inherits
)
1221 (declare (type defstruct-description dd
))
1223 (aver (dd-class-p dd
)) ; LIST and VECTOR representation are not allowed
1224 (let ((check-inlining
1225 ;; Why use the secondary result of INFO, not the primary?
1226 ;; Because when DEFSTRUCT is evaluated, not via the file-compiler,
1227 ;; the first thing to happen is %DEFSTRUCT, which sets up FIND-CLASS.
1228 ;; Due to :COMPILER-LAYOUT's defaulting expression in globaldb,
1229 ;; it has a value - the layout of the classoid - that we don't want.
1230 ;; Also, since structures are technically not redefineable,
1231 ;; I don't worry about failure to inline a function that was
1232 ;; formerly not known as an accessor but now is.
1233 (null (nth-value 1 (info :type
:compiler-layout
(dd-name dd
)))))
1235 (%compiler-set-up-layout dd inherits
)
1236 (%proclaim-defstruct-ctors dd
)
1238 (awhen (dd-copier-name dd
)
1239 (let ((dtype (dd-name dd
)))
1240 (sb!xc
:proclaim
`(ftype (sfunction (,dtype
) ,dtype
) ,it
))))
1242 (let ((predicate-name (dd-predicate-name dd
)))
1243 (when predicate-name
1244 (when check-inlining
1245 (push predicate-name fnames
))
1246 (setf (info :function
:source-transform predicate-name
)
1247 (cons dd
:predicate
))))
1249 (dolist (dsd (dd-slots dd
))
1250 (let ((accessor-name (dsd-accessor-name dsd
)))
1251 ;; Why this WHEN guard here, if there is neither a standards-specified
1252 ;; nor implementation-specific way to skip defining an accessor? Dunno.
1253 ;; And furthermore, by ignoring a package lock, it's possible to name
1254 ;; an accessor NIL: (defstruct (x (:conc-name "N")) IL)
1255 ;; making this test kinda bogus in two different ways.
1257 (let ((inherited (accessor-inherited-data accessor-name dd
)))
1260 (let ((writer `(setf ,accessor-name
))
1261 (slot-key (cons dd dsd
)))
1262 (when check-inlining
1263 (push accessor-name fnames
))
1264 (setf (info :function
:source-transform accessor-name
)
1266 (unless (dsd-read-only dsd
)
1267 (when check-inlining
1268 (push writer fnames
))
1269 (setf (info :function
:source-transform writer
) slot-key
))))
1270 ((not (= (cdr inherited
) (dsd-index dsd
)))
1271 (style-warn "~@<Non-overwritten accessor ~S does not access ~
1272 slot with name ~S (accessing an inherited slot ~
1275 (dsd-name dsd
))))))))
1277 (awhen (remove-if-not #'sb
!c
::emitted-full-call-count fnames
)
1278 (sb!c
:compiler-style-warn
1279 'sb
!c
:inlining-dependency-failure
1280 ;; This message omits the http://en.wikipedia.org/wiki/Serial_comma
1281 :format-control
"~@<Previously compiled call~P to ~
1282 ~{~/sb!impl:print-symbol-with-prefix/~^~#[~; and~:;,~] ~} ~
1283 could not be inlined because the structure definition for ~
1284 ~/sb!impl:print-symbol-with-prefix/ was not yet seen. To avoid this warning, ~
1285 DEFSTRUCT should precede references to the affected functions, ~
1286 or they must be declared locally notinline at each call site.~@:>"
1287 :format-arguments
(list (length it
) (nreverse it
) (dd-name dd
))))))
1289 ;;;; redefinition stuff
1291 ;;; Compare the slots of OLD and NEW, returning 3 lists of slot names:
1292 ;;; 1. Slots which have moved,
1293 ;;; 2. Slots whose type has changed,
1294 ;;; 3. Deleted slots.
1295 (defun compare-slots (old new
)
1296 (let* ((oslots (dd-slots old
))
1297 (nslots (dd-slots new
))
1298 (onames (mapcar #'dsd-name oslots
))
1299 (nnames (mapcar #'dsd-name nslots
)))
1302 (dolist (name (intersection onames nnames
))
1303 (let ((os (find name oslots
:key
#'dsd-name
:test
#'string
=))
1304 (ns (find name nslots
:key
#'dsd-name
:test
#'string
=)))
1305 (unless (sb!xc
:subtypep
(dsd-type ns
) (dsd-type os
))
1307 (unless (and (= (dsd-index os
) (dsd-index ns
))
1308 (eq (dsd-raw-type os
) (dsd-raw-type ns
)))
1312 (set-difference onames nnames
:test
#'string
=)))))
1314 ;;; If we are redefining a structure with different slots than in the
1315 ;;; currently loaded version, give a warning and return true.
1316 (defun redefine-structure-warning (classoid old new
)
1317 (declare (type defstruct-description old new
)
1318 (type classoid classoid
)
1320 (let ((name (dd-name new
)))
1321 (multiple-value-bind (moved retyped deleted
) (compare-slots old new
)
1322 (when (or moved retyped deleted
)
1324 "incompatibly redefining slots of structure class ~S~@
1325 Make sure any uses of affected accessors are recompiled:~@
1326 ~@[ These slots were moved to new positions:~% ~S~%~]~
1327 ~@[ These slots have new incompatible types:~% ~S~%~]~
1328 ~@[ These slots were deleted:~% ~S~%~]"
1329 name moved retyped deleted
)
1332 ;;; Return true if destructively modifying OLD-LAYOUT into NEW-LAYOUT
1333 ;;; would be possible in as much as it won't harm the garbage collector.
1334 ;;; Harm potentially results from turning a raw word into a tagged word.
1335 (defun mutable-layout-p (old-layout new-layout
)
1336 (let ((old-bitmap (layout-bitmap old-layout
))
1337 (new-bitmap (layout-bitmap new-layout
)))
1338 (assert (= old-bitmap
(dd-bitmap (layout-info old-layout
))))
1339 (assert (= new-bitmap
(dd-bitmap (layout-info new-layout
))))
1340 (dotimes (i (dd-length (layout-info old-layout
)) t
)
1341 (when (and (logbitp i new-bitmap
) ; a tagged (i.e. scavenged) slot
1342 (not (logbitp i old-bitmap
))) ; that was opaque bits
1345 ;;; This function is called when we are incompatibly redefining a
1346 ;;; structure CLASS to have the specified NEW-LAYOUT. We signal an
1347 ;;; error with some proceed options and return the layout that should
1349 (defun %redefine-defstruct
(classoid old-layout new-layout
)
1350 (declare (type classoid classoid
)
1351 (type layout old-layout new-layout
))
1352 (let ((name (classoid-proper-name classoid
)))
1354 (error "~@<attempt to redefine the ~S class ~S incompatibly with the current definition~:@>"
1360 "~@<Use the new definition of ~S, invalidating ~
1361 already-loaded code and instances.~@:>"
1363 (register-layout new-layout
))
1364 (recklessly-continue ()
1366 (declare (ignore c
))
1367 (mutable-layout-p old-layout new-layout
))
1370 "~@<Use the new definition of ~S as if it were ~
1371 compatible, allowing old accessors to use new ~
1372 instances and allowing new accessors to use old ~
1375 ;; classic CMU CL warning: "Any old ~S instances will be in a bad way.
1376 ;; I hope you know what you're doing..."
1377 (register-layout new-layout
1379 :destruct-layout old-layout
))))
1382 ;;; Compute DD's bitmap, storing 1 for each tagged word.
1383 ;;; The bitmap should be stored as a negative fixnum in two cases:
1384 ;;; (1) if the positive value is a bignum but the negative is a fixnum.
1385 ;;; (2) if there are no raw slots at all.
1386 ;;; Example: given (DEFSTRUCT S A B C), the computed bitmap is #b11111 -
1387 ;;; one bit for the layout; one each for A, B, C; and one for padding.
1388 ;;; Whether this is stored as 31 or -1 is mostly immaterial,
1389 ;;; but -1 is preferable because GC has a special case for it.
1390 ;;; Suppose instead we have 1 untagged word followed by N tagged words
1391 ;;; for N > n-fixnum-bits. The computed bitmap is #b111...11101
1392 ;;; but the sign-extended value is -3, which is a fixnum.
1393 ;;; If both the + and - values are fixnums, and raw slots are present,
1394 ;;; we'll choose the positive value.
1395 (defun dd-bitmap (dd)
1396 ;; With compact instances, LAYOUT is not reflected in the bitmap.
1397 ;; Without compact instances, the 0th bitmap bit (for the LAYOUT) is always 1.
1398 ;; In neither case is the place for the layout represented in in DD-SLOTS.
1399 (let ((bitmap sb
!vm
:instance-data-start
))
1400 (dolist (slot (dd-slots dd
))
1401 (when (eql t
(dsd-raw-type slot
))
1402 (setf bitmap
(logior bitmap
(ash 1 (dsd-index slot
))))))
1403 (let* ((length (dd-length dd
))
1404 (n-bits (logior length
1)))
1405 (when (evenp length
) ; Add padding word if necessary.
1406 (setq bitmap
(logior bitmap
(ash 1 length
))))
1407 (when (logbitp (1- n-bits
) bitmap
)
1408 (let ((sign-ext (logior (ash -
1 n-bits
) bitmap
)))
1409 (when (or (and (fixnump sign-ext
) (sb!xc
:typep bitmap
'bignum
))
1411 (return-from dd-bitmap sign-ext
)))))
1414 ;;; This is called when we are about to define a structure class. It
1415 ;;; returns a (possibly new) class object and the layout which should
1416 ;;; be used for the new definition (may be the current layout, and
1417 ;;; also might be an uninstalled forward referenced layout.) The third
1418 ;;; value is true if this is an incompatible redefinition, in which
1419 ;;; case it is the old layout.
1420 (defun ensure-structure-class (info inherits old-context new-context
1421 &key compiler-layout
)
1422 (declare (type defstruct-description info
))
1423 (multiple-value-bind (classoid old-layout
)
1424 (multiple-value-bind (class constructor
)
1425 (acond ((cdr (dd-alternate-metaclass info
))
1426 (values (first it
) (second it
)))
1428 (values 'structure-classoid
'make-structure-classoid
)))
1429 (insured-find-classoid (dd-name info
)
1430 (if (eq class
'structure-classoid
)
1432 (sb!xc
:typep x
'structure-classoid
))
1434 (sb!xc
:typep x
(classoid-name (find-classoid class
)))))
1435 (fdefinition constructor
)))
1436 (setf (classoid-direct-superclasses classoid
)
1437 (case (dd-name info
)
1440 sb
!impl
::string-input-stream sb
!impl
::string-output-stream
1441 sb
!impl
::fill-pointer-output-stream
)
1442 (list (layout-classoid (svref inherits
(1- (length inherits
))))
1443 (layout-classoid (svref inherits
(- (length inherits
) 2)))))
1445 (list (layout-classoid
1446 (svref inherits
(1- (length inherits
))))))))
1447 (let* ((old-layout (or compiler-layout old-layout
))
1448 (flags (if (dd-alternate-metaclass info
) 0 +structure-layout-flag
+))
1450 (when (or (not old-layout
) *type-system-initialized
*)
1451 (make-layout :classoid classoid
1454 :depthoid
(length inherits
)
1455 :length
(dd-length info
)
1457 :bitmap
(dd-bitmap info
)))))
1460 (values classoid new-layout nil
))
1462 ;; The assignment of INFO here can almost be deleted,
1463 ;; except for a few magical types that don't d.t.r.t. in cold-init:
1464 ;; STRUCTURE-OBJECT, CONDITION, ALIEN-VALUE, INTERPRETED-FUNCTION
1465 (setf (layout-info old-layout
) info
)
1466 (values classoid old-layout nil
))
1467 (;; This clause corresponds to an assertion in REDEFINE-LAYOUT-WARNING
1468 ;; of classic CMU CL. I moved it out to here because it was only
1469 ;; exercised in this code path anyway. -- WHN 19990510
1470 (not (eq (layout-classoid new-layout
) (layout-classoid old-layout
)))
1471 (error "shouldn't happen: weird state of OLD-LAYOUT?"))
1472 ((redefine-layout-warning old-context
1475 (layout-length new-layout
)
1476 (layout-inherits new-layout
)
1477 (layout-depthoid new-layout
)
1478 (layout-bitmap new-layout
))
1479 (values classoid new-layout old-layout
))
1481 (let ((old-info (layout-info old-layout
)))
1483 (cond ((redefine-structure-warning classoid old-info info
)
1484 (values classoid new-layout old-layout
))
1486 (setf (layout-info old-layout
) info
)
1487 (values classoid old-layout nil
)))
1489 (setf (layout-info old-layout
) info
)
1490 (values classoid old-layout nil
)))))))))
1492 ;;; Return a list of pairs (name . index). Used for :TYPE'd
1493 ;;; constructors to find all the names that we have to splice in &
1494 ;;; where. Note that these types don't have a layout, so we can't look
1495 ;;; at LAYOUT-INHERITS.
1496 (defun find-name-indices (defstruct)
1499 (do ((info defstruct
1500 (typed-structure-info-or-lose (first (dd-include info
)))))
1501 ((not (dd-include info
))
1506 (dolist (info infos
)
1507 (incf i
(or (dd-offset info
) 0))
1508 (when (dd-named info
)
1509 (res (cons (dd-name info
) i
)))
1510 (setq i
(dd-length info
)))))
1514 ;;; These functions are called to actually make a constructor after we
1515 ;;; have processed the arglist. The correct variant (according to the
1516 ;;; DD-TYPE) should be called. The function is defined with the
1517 ;;; specified name and arglist. VARS and TYPES are used for argument
1518 ;;; type declarations. VALUES are the values for the slots (in order.)
1520 ;;; This is split into two functions:
1521 ;;; * INSTANCE-CONSTRUCTOR-FORM has to deal with raw slots
1522 ;;; (there are two variations on this)
1523 ;;; * TYPED-CONSTRUCTOR-FORM deal with LIST & VECTOR
1524 ;;; which might have "name" symbols stuck in at various weird places.
1525 (defun instance-constructor-form (dd values
)
1526 ;; The difference between the two implementations here is that on all
1527 ;; platforms we don't have the appropriate RAW-INSTANCE-INIT VOPS, which
1528 ;; must be able to deal with immediate values as well -- unlike
1529 ;; RAW-INSTANCE-SET VOPs, which never end up seeing immediate values. With
1530 ;; some additional cleverness we might manage without them and just a single
1531 ;; implementation here, though -- figure out a way to ensure that on those
1532 ;; platforms we always still get a non-immediate TN in every case...
1534 ;; Until someone does that, this means that instances with raw slots can be
1535 ;; DX allocated only on platforms with those additional VOPs.
1536 (let ((dd-slots (dd-slots dd
)))
1537 (aver (= (length dd-slots
) (length values
)))
1538 #!+raw-instance-init-vops
1539 (collect ((slot-specs) (slot-values))
1540 (mapc (lambda (dsd value
&aux
(raw-type (dsd-raw-type dsd
))
1541 (spec (list* :slot raw-type
(dsd-index dsd
))))
1542 (cond ((eq value
'.do-not-initialize-slot.
)
1543 (when (eq raw-type t
)
1544 (rplaca spec
:unbound
)
1548 (slot-values value
))))
1550 `(%make-structure-instance-macro
,dd
',(slot-specs) ,@(slot-values)))
1551 #!-raw-instance-init-vops
1552 (collect ((slot-specs) (slot-values) (raw-slots) (raw-values))
1553 ;; Partition into non-raw and raw
1554 (mapc (lambda (dsd value
&aux
(raw-type (dsd-raw-type dsd
))
1555 (spec (list* :slot raw-type
(dsd-index dsd
))))
1556 (cond ((eq value
'.do-not-initialize-slot.
)
1557 (when (eq raw-type t
)
1558 (rplaca spec
:unbound
)
1562 (slot-values value
))
1565 (raw-values value
))))
1567 (let ((instance-form
1568 `(%make-structure-instance-macro
,dd
1569 ',(slot-specs) ,@(slot-values))))
1571 (let ((temp (make-symbol "INSTANCE")))
1572 `(let ((,temp
,instance-form
))
1573 ;; Transform to %RAW-INSTANCE-SET/foo, not SETF,
1574 ;; in case any slots are readonly.
1575 ,@(mapcar (lambda (dsd value
)
1576 (slot-access-transform
1577 :setf
(list temp value
) (cons dd dsd
)))
1578 (raw-slots) (raw-values))
1582 ;;; A "typed" constructor prefers to use a single call to LIST or VECTOR
1583 ;;; if possible, but can't always do that for VECTOR because it might not
1584 ;;; be a (VECTOR T). If not, we fallback to MAKE-ARRAY and (SETF AREF).
1585 (defun typed-constructor-form (dd values
)
1586 (multiple-value-bind (operator initial-element
)
1587 (cond ((and (eq (dd-type dd
) 'vector
) (eq (dd-element-type dd
) t
))
1589 ((eq (dd-type dd
) 'list
)
1590 (values 'list nil
)))
1591 (let* ((length (dd-length dd
))
1592 (slots (dd-slots dd
))
1593 ;; Possibly the most useless feature ever: more than one name slot.
1594 (names (find-name-indices dd
)))
1595 (aver (= (length slots
) (length values
)))
1597 ;; The initial-element provides values for slots that are skipped
1598 ;; due to :initial-offset, not slots that are skipped due to
1599 ;; &AUX variables with no initial value.
1600 (let ((vals (make-list length
:initial-element initial-element
)))
1602 (setf (elt vals
(cdr x
)) `',(car x
)))
1603 (mapc (lambda (dsd val
)
1604 ;; For both vectors and lists, .DO-NOT-INITIALIZE-SLOT.
1605 ;; becomes 0 even though lists otherwise use NIL for slots
1606 ;; that are skipped to due :initial-offset.
1607 (setf (elt vals
(dsd-index dsd
))
1608 ;; All VALs have been wrapped in THE if necessary.
1609 (if (eq val
'.do-not-initialize-slot.
) 0 val
)))
1611 (cons operator vals
))
1612 (let ((temp (make-symbol "OBJ")))
1613 `(let ((,temp
(make-array ,length
1614 :element-type
',(dd-element-type dd
))))
1615 ,@(mapcar (lambda (x) `(setf (aref ,temp
,(cdr x
)) ',(car x
)))
1617 ,@(mapcan (lambda (dsd val
)
1618 (unless (eq val
'.do-not-initialize-slot.
)
1619 `((setf (aref ,temp
,(dsd-index dsd
)) ,val
))))
1623 ;;; Return the FTYPE for a DD constructor.
1624 ;;; This is tricky in uses such as the following:
1625 ;;; (DEFSTRUCT (S (:CONSTRUCTOR MS (A &AUX (A (ABS A))))) (A 0 :TYPE (MOD 4)))
1626 ;;; The constructor accepts integers betweeen -3 and 3 because the &AUX binding
1627 ;;; hides the positional argument A, and we can't actually put any constraint
1628 ;;; on A unless we figure out what the action of ABS is.
1630 ;;; The FTYPE is actually not a strong enough constraint anyway, so when IR1
1631 ;;; tests for the call compatibility it will test for correctness *after*
1632 ;;; argument defaulting.
1633 (defun %struct-ctor-ftype
(dd args elt-type
)
1634 (flet ((elt-type-intersect (dsd &aux
(slot-type (dsd-type dsd
)))
1635 (cond ((eq slot-type t
) elt-type
)
1636 ((eq elt-type t
) slot-type
)
1637 (t `(and ,elt-type
,slot-type
)))))
1639 ,(if (eq args
:default
)
1640 `(&key
,@(mapcar (lambda (dsd)
1641 `(,(keywordicate (dsd-name dsd
))
1642 ,(elt-type-intersect dsd
)))
1644 (destructuring-bind (llks &optional req opt rest keys aux
) args
1645 (let ((aux (mapcar (lambda (var) (if (listp var
) (car var
) var
))
1647 (flet ((get-arg-type (name)
1648 (let ((slot (unless (member name aux
:test
#'string
=)
1649 (find name
(dd-slots dd
) :key
#'dsd-name
1651 ;; If no slot, the arg restriction is T,
1652 ;; because we don't know where it goes.
1653 (if slot
(elt-type-intersect slot
) t
))))
1655 llks nil
(mapcar #'get-arg-type req
)
1656 (mapcar (lambda (arg)
1657 (get-arg-type (parse-optional-arg-spec arg
)))
1660 (mapcar (lambda (arg)
1661 (multiple-value-bind (key var
) (parse-key-arg-spec arg
)
1662 `(,key
,(get-arg-type var
))))
1664 (values ,(cond ((dd-class-p dd
) (dd-name dd
))
1665 ((eq (dd-type dd
) 'list
) 'list
)
1666 (t `(vector ,(dd-element-type dd
) ,(dd-length dd
))))
1669 (defun struct-ctor-ftype (dd name
)
1670 (let ((ctor (assq name
(dd-constructors dd
))))
1672 (%struct-ctor-ftype dd
(cdr ctor
) (dd-element-type dd
))))
1674 (defun proclaimed-ftype (name)
1675 (multiple-value-bind (info foundp
) (info :function
:type name
)
1676 (values (cond ((defstruct-description-p info
)
1677 (specifier-type (struct-ctor-ftype info name
)))
1678 #-sb-xc-host
; PCL doesn't exist
1679 ((eq info
:generic-function
) (sb!pcl
::compute-gf-ftype name
))
1683 ;;; Given a DD and a constructor spec (a cons of name and pre-parsed
1684 ;;; BOA lambda list, or the symbol :DEFAULT), return the effective
1685 ;;; lambda list and the body of the lambda.
1686 (defun structure-ctor-lambda-parts
1687 (dd args
&aux
(creator (ecase (dd-type dd
)
1688 (structure #'instance-constructor-form
)
1689 ((list vector
) #'typed-constructor-form
))))
1690 (when (eq args
:default
)
1691 (let ((lambda-list (mapcar (lambda (dsd)
1692 (let* ((temp (copy-symbol (dsd-name dsd
)))
1693 (keyword (keywordicate temp
)))
1694 `((,keyword
,temp
) ,(dsd-default dsd
))))
1696 (return-from structure-ctor-lambda-parts
1697 `((&key
,@lambda-list
)
1698 (declare (explicit-check))
1699 ,(funcall creator dd
1700 (mapcar (lambda (dsd arg
)
1701 (let ((type (dsd-type dsd
))
1705 `(the* (,type
:context
1706 (:struct
,(dd-name dd
) .
,(dsd-name dsd
)))
1708 (dd-slots dd
) lambda-list
))))))
1709 (destructuring-bind (llks &optional req opt rest keys aux
) args
1710 (collect ((vars (copy-list req
)) ; list of bound vars
1713 (dolist (binding aux
)
1714 (let ((name (if (listp binding
) (car binding
) binding
)))
1716 (unless (typep binding
'(cons t cons
))
1717 (skipped-vars name
))))
1718 (macrolet ((rewrite (input key parse
)
1721 (multiple-value-bind (,@key var def sup-p
) (,parse arg
)
1722 (declare (ignore ,@key def
))
1723 (rewrite-1 arg var sup-p
)))
1725 (flet ((rewrite-1 (arg var sup-p-var
)
1727 (when sup-p-var
(vars (car sup-p-var
)))
1728 (let* ((slot (unless (member var
(aux-vars) :test
#'string
=)
1729 (find var
(dd-slots dd
)
1730 :key
#'dsd-name
:test
#'string
=)))
1731 (default (and slot
(dsd-default slot
))))
1732 ;; If VAR initializes a slot and did not have a default in
1733 ;; the lambda list, and DSD-DEFAULT is not NIL,
1734 ;; then change the lambda-list's default for the variable.
1735 ;; Always prefer to insert (CAR ARG) if ARG was a list
1736 ;; so that (:KEY var) syntax is preserved.
1737 (if (and slot
(not (typep arg
'(cons t cons
))) default
)
1738 `(,(if (consp arg
) (car arg
) var
) ,default
,@sup-p-var
)
1739 arg
)))) ; keep it as it was
1740 ;; Can we substitute symbols that are not EQ to symbols
1741 ;; naming slots, so we don't have to compare by STRING= later?
1742 ;; Probably not because other symbols could reference them.
1743 (setq opt
(rewrite opt
() parse-optional-arg-spec
))
1744 (when rest
(vars (car rest
)))
1745 (setq keys
(rewrite keys
(key) parse-key-arg-spec
))
1746 (dolist (arg (aux-vars)) (vars arg
))))
1747 `(,(sb!c
::make-lambda-list
1748 llks nil req opt rest keys
1749 ;; &AUX vars which do not initialize a slot are not mentioned
1750 ;; in the lambda list, though it's not clear what to do if
1751 ;; subsequent bindings refer to the deleted ones.
1752 ;; And worse, what if it's SETQd - is that even legal?
1753 (remove-if (lambda (x) (not (typep x
'(cons t cons
)))) aux
))
1754 (declare (explicit-check))
1758 (lambda (slot &aux
(name (dsd-name slot
)))
1759 (if (find name
(skipped-vars) :test
#'string
=)
1760 ;; CLHS 3.4.6 Boa Lambda Lists
1761 '.do-not-initialize-slot.
1762 (let* ((type (dsd-type slot
))
1763 (found (member (dsd-name slot
) (vars) :test
#'string
=))
1764 (initform (if found
(car found
) (dsd-default slot
))))
1765 ;; We can ignore the DD-ELEMENT-TYPE
1766 ;; because the container itself will check.
1767 (if (eq type t
) initform
`(the ,type
,initform
)))))
1770 (defun accessor-definitions (dd *pending-defstruct-type
*)
1771 (loop for dsd in
(dd-slots dd
)
1772 for accessor-name
= (dsd-accessor-name dsd
)
1773 unless
(accessor-inherited-data accessor-name dd
)
1774 nconc
(dx-let ((key (cons dd dsd
)))
1775 `(,@(unless (dsd-read-only dsd
)
1776 `((defun (setf ,accessor-name
) (value instance
)
1777 ,(slot-access-transform :setf
'(instance value
) key
))))
1778 (defun ,accessor-name
(instance)
1779 ,(slot-access-transform :read
'(instance) key
))))))
1781 ;;;; instances with ALTERNATE-METACLASS
1783 ;;;; The CMU CL support for structures with ALTERNATE-METACLASS was a
1784 ;;;; fairly general extension embedded in the main DEFSTRUCT code, and
1785 ;;;; the result was an fairly impressive mess as ALTERNATE-METACLASS
1786 ;;;; extension mixed with ANSI CL generality (e.g. :TYPE and :INCLUDE)
1787 ;;;; and CMU CL implementation hairiness (esp. raw slots). This SBCL
1788 ;;;; version is much less ambitious, noticing that ALTERNATE-METACLASS
1789 ;;;; is only used to implement CONDITION, STANDARD-INSTANCE, and
1790 ;;;; GENERIC-FUNCTION, and defining a simple specialized
1791 ;;;; separate-from-DEFSTRUCT macro to provide only enough
1792 ;;;; functionality to support those.
1794 ;;;; KLUDGE: The defining macro here is so specialized that it's ugly
1795 ;;;; in its own way. It also violates once-and-only-once by knowing
1796 ;;;; much about structures and layouts that is already known by the
1797 ;;;; main DEFSTRUCT macro. Hopefully it will go away presently
1798 ;;;; (perhaps when CL:CLASS and SB-PCL:CLASS meet) as per FIXME below.
1799 ;;;; -- WHN 2001-10-28
1801 ;;;; FIXME: There seems to be no good reason to shoehorn CONDITION,
1802 ;;;; STANDARD-INSTANCE, and GENERIC-FUNCTION into mutated structures
1803 ;;;; instead of just implementing them as primitive objects. (This
1804 ;;;; reduced-functionality macro seems pretty close to the
1805 ;;;; functionality of !DEFINE-PRIMITIVE-OBJECT..)
1807 ;;; The complete list of alternate-metaclass DEFSTRUCTs:
1808 ;;; CONDITION SB-EVAL:INTERPRETED-FUNCTION
1809 ;;; SB-PCL::STANDARD-INSTANCE SB-PCL::STANDARD-FUNCALLABLE-INSTANCE
1810 ;;; SB-PCL::CTOR SB-PCL::%METHOD-FUNCTION
1812 (defun make-dd-with-alternate-metaclass (&key
(class-name (missing-arg))
1813 (superclass-name (missing-arg))
1814 (metaclass-name (missing-arg))
1815 (dd-type (missing-arg))
1816 metaclass-constructor
1818 (let* ((dd (make-defstruct-description t class-name
))
1819 (conc-name (string (gensymify* class-name
"-")))
1820 ;; Without compact instance headers, the index starts at 1 for
1821 ;; named slots, because slot 0 is the LAYOUT.
1822 ;; This is the same in ordinary structures too: see (INCF DD-LENGTH)
1823 ;; in PARSE-DEFSTRUCT-NAME-AND-OPTIONS.
1824 ;; With compact instance headers, slot 0 is a data slot.
1825 (slot-index sb
!vm
:instance-data-start
))
1826 ;; We do *not* fill in the COPIER-NAME and PREDICATE-NAME
1827 ;; because alternate-metaclass structures can not have either.
1829 ;; We don't support inheritance of alternate metaclass stuff,
1830 ;; and it's not a general-purpose facility, so sanity check our
1833 (aver (eq superclass-name
't
)))
1834 (funcallable-structure
1835 (aver (eq superclass-name
'function
)))
1836 (t (bug "Unknown DD-TYPE in ALTERNATE-METACLASS: ~S" dd-type
)))
1837 (setf (dd-alternate-metaclass dd
) (list superclass-name
1839 metaclass-constructor
)
1841 (mapcar (lambda (slot-name)
1842 (make-dsd slot-name t
(symbolicate conc-name slot-name
)
1843 (pack-dsd-bits (prog1 slot-index
(incf slot-index
))
1847 (dd-length dd
) slot-index
1848 (dd-type dd
) dd-type
)
1851 ;;; make !DEFSTRUCT-WITH-ALTERNATE-METACLASS compilable by the host
1852 ;;; lisp, installing the information we need to reason about the
1853 ;;; structures (layouts and classoids).
1855 ;;; FIXME: we should share the parsing and the DD construction between
1856 ;;; this and the cross-compiler version, but my brain was too small to
1857 ;;; get that right. -- CSR, 2006-09-14
1859 (defmacro !defstruct-with-alternate-metaclass
1861 (slot-names (missing-arg))
1862 (boa-constructor (missing-arg))
1863 (superclass-name (missing-arg))
1864 (metaclass-name (missing-arg))
1865 (metaclass-constructor (missing-arg))
1866 (dd-type (missing-arg))
1867 (runtime-type-checks-p t
))
1869 (declare (type (and list
(not null
)) slot-names
))
1870 (declare (type (and symbol
(not null
))
1874 metaclass-constructor
))
1875 (declare (type (member structure funcallable-structure
) dd-type
))
1876 (declare (ignore boa-constructor runtime-type-checks-p
))
1878 (let* ((dd (make-dd-with-alternate-metaclass
1879 :class-name class-name
1880 :slot-names slot-names
1881 :superclass-name superclass-name
1882 :metaclass-name metaclass-name
1883 :metaclass-constructor metaclass-constructor
1887 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
1888 (%compiler-set-up-layout
',dd
',(!inherits-for-structure dd
))))))
1890 (sb!xc
:defmacro
!defstruct-with-alternate-metaclass
1892 (slot-names (missing-arg))
1893 (boa-constructor (missing-arg))
1894 (superclass-name (missing-arg))
1895 (metaclass-name (missing-arg))
1896 (metaclass-constructor (missing-arg))
1897 (dd-type (missing-arg))
1898 (runtime-type-checks-p t
))
1900 (declare (type (and list
(not null
)) slot-names
))
1901 (declare (type (and symbol
(not null
))
1905 metaclass-constructor
))
1906 (declare (type (member structure funcallable-structure
) dd-type
))
1908 (let* ((dd (make-dd-with-alternate-metaclass
1909 :class-name class-name
1910 :slot-names slot-names
1911 :superclass-name superclass-name
1912 :metaclass-name metaclass-name
1913 :metaclass-constructor metaclass-constructor
1915 (dd-slots (dd-slots dd
))
1916 (dd-length (dd-length dd
))
1917 (object-gensym (make-symbol "OBJECT"))
1918 (new-value-gensym (make-symbol "NEW-VALUE"))
1919 (delayed-layout-form `(%delayed-get-compiler-layout
,class-name
)))
1920 (multiple-value-bind (raw-maker-form raw-reffer-operator
)
1923 (values `(%make-structure-instance-macro
,dd nil
)
1925 (funcallable-structure
1926 (values `(let ((,object-gensym
1927 ;; TRULY-THE should not be needed. But it is, to avoid
1928 ;; a type check on the next SETF. Why???
1929 (truly-the funcallable-instance
1930 (%make-funcallable-instance
,dd-length
))))
1931 (setf (%funcallable-instance-layout
,object-gensym
)
1932 ,delayed-layout-form
)
1934 '%funcallable-instance-info
)))
1937 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
1938 (%compiler-set-up-layout
',dd
',(!inherits-for-structure dd
)))
1940 ;; slot readers and writers
1941 (declaim (inline ,@(mapcar #'dsd-accessor-name dd-slots
)))
1942 ,@(mapcar (lambda (dsd)
1943 `(defun ,(dsd-accessor-name dsd
) (,object-gensym
)
1944 ,@(when runtime-type-checks-p
1945 `((declare (type ,class-name
,object-gensym
))))
1946 (,raw-reffer-operator
,object-gensym
1949 (declaim (inline ,@(mapcar (lambda (dsd)
1950 `(setf ,(dsd-accessor-name dsd
)))
1952 ,@(mapcar (lambda (dsd)
1953 `(defun (setf ,(dsd-accessor-name dsd
)) (,new-value-gensym
1955 ,@(when runtime-type-checks-p
1956 `((declare (type ,class-name
,object-gensym
))))
1957 (setf (,raw-reffer-operator
,object-gensym
1959 ,new-value-gensym
)))
1963 (defun ,boa-constructor
,slot-names
1964 (let ((,object-gensym
,raw-maker-form
))
1965 ,@(mapcar (lambda (slot-name)
1966 (let ((dsd (or (find slot-name dd-slots
1967 :key
#'dsd-name
:test
#'string
=)
1968 (bug "Bogus alt-metaclass boa ctor"))))
1969 `(setf (,(dsd-accessor-name dsd
) ,object-gensym
)
1974 ;; Usually we AVER instead of ASSERT, but AVER isn't defined yet.
1975 ;; A naive reading of 'build-order' suggests it is,
1976 ;; but due to def!struct delay voodoo, it isn't.
1977 (assert (null (symbol-value '*defstruct-hooks
*)))))))
1979 ;;;; finalizing bootstrapping
1981 ;;; Set up DD and LAYOUT for STRUCTURE-OBJECT class itself.
1983 ;;; Ordinary structure classes effectively :INCLUDE STRUCTURE-OBJECT
1984 ;;; when they have no explicit :INCLUDEs, so (1) it needs to be set up
1985 ;;; before we can define ordinary structure classes, and (2) it's
1986 ;;; special enough (and simple enough) that we just build it by hand
1987 ;;; instead of trying to generalize the ordinary DEFSTRUCT code.
1988 (defun !set-up-structure-object-class
()
1989 (let ((dd (make-defstruct-description t
'structure-object
)))
1992 (dd-length dd
) sb
!vm
:instance-data-start
1993 (dd-type dd
) 'structure
)
1994 (%compiler-set-up-layout dd
)))
1995 #+sb-xc-host
(!set-up-structure-object-class
)
1997 (defun find-defstruct-description (name &optional
(errorp t
))
1998 (let* ((classoid (find-classoid name errorp
))
2000 (layout-info (classoid-layout classoid
)))))
2001 (cond ((defstruct-description-p info
)
2004 (error "No DEFSTRUCT-DESCRIPTION for ~S." name
)))))
2006 (defun structure-instance-accessor-p (name)
2007 (let ((info (info :function
:source-transform name
)))
2009 (defstruct-slot-description-p (cdr info
))
2012 (defun dd-default-constructor (dd)
2013 (let ((ctor (first (dd-constructors dd
))))
2014 (when (typep ctor
'(cons t
(eql :default
)))
2017 ;;; These functions are required to emulate SBCL kernel functions
2018 ;;; in a vanilla ANSI Common Lisp cross-compilation host.
2019 ;;; The emulation doesn't need to be efficient, since it's needed
2020 ;;; only for object dumping.
2023 (defun %instance-layout
(instance)
2024 (classoid-layout (find-classoid (type-of instance
))))
2025 (defun %instance-length
(instance)
2026 ;; In the target, it is theoretically possible to have %INSTANCE-LENGTH
2027 ;; exceeed layout length, but in the cross-compiler they're the same.
2028 (layout-length (%instance-layout instance
)))
2029 (defun %instance-ref
(instance index
)
2030 (let ((layout (%instance-layout instance
)))
2031 ;; with compact headers, 0 is an ordinary slot index.
2032 ;; without, it's the layout.
2033 (if (eql index
(1- sb
!vm
:instance-data-start
))
2034 (error "XC Host should use %INSTANCE-LAYOUT, not %INSTANCE-REF 0")
2035 (let* ((dd (layout-info layout
))
2036 ;; If data starts at 1, then subtract 1 from index.
2037 ;; otherwise use the index as-is.
2038 (dsd (elt (dd-slots dd
)
2039 (- index sb
!vm
:instance-data-start
)))
2040 (accessor-name (dsd-accessor-name dsd
)))
2041 ;; Why AVER these: because it is slightly abstraction-breaking
2042 ;; to assume that the slot-index N is the NTH item in the DSDs.
2043 ;; The target Lisp never assumes that.
2044 (aver (and (eql (dsd-index dsd
) index
) (eq (dsd-raw-type dsd
) t
)))
2045 (funcall accessor-name instance
)))))
2047 (defun %raw-instance-ref
/word
(instance index
)
2048 (declare (ignore instance index
))
2049 (error "No such thing as raw structure access on the host"))
2051 ;; Setting with (FUNCALL `(SETF ,accessor) ...) is unportable because
2052 ;; "The mechanism by which defstruct arranges for slot accessors to be
2053 ;; usable with setf is implementation-dependent; for example, it may
2054 ;; use setf functions, setf expanders, or some other
2055 ;; implementation-dependent mechanism ..."
2056 ;; But such capability seems not to be needed.
2057 (defun %instance-set
(instance index new-value
)
2058 (declare (ignore instance index new-value
))
2059 (error "Can not use %INSTANCE-SET on cross-compilation host.")))
2061 ;;; If LAMBDA-LIST and BODY constitute an auto-generated structure function
2062 ;;; (accessor or predicate) for NAME, return the kind of thing it is.
2063 (defun defstruct-generated-defn-p (name lambda-list body
)
2064 (unless (singleton-p body
)
2065 (return-from defstruct-generated-defn-p nil
))
2066 (let ((info (info :function
:source-transform name
))
2069 (when (and (eq (cdr info
) :predicate
)
2070 (equal lambda-list
'(object))
2074 (cons (cons (eql quote
) (cons t null
))
2076 ;; extract dd-name from `(TYPEP OBJECT ',THING)
2077 (eq (second (third form
)) (dd-name (car info
))))
2078 (return-from defstruct-generated-defn-p
:predicate
))
2079 (when (defstruct-slot-description-p (cdr info
))
2080 (multiple-value-bind (mode expected-lambda-list xform-args
)
2082 (values :setf
'(value instance
) '(instance value
))
2083 (values :read
'(instance) '(instance)))
2084 (when (and (equal expected-lambda-list lambda-list
)
2085 (equal (slot-access-transform mode xform-args info
) form
))
2086 (return-from defstruct-generated-defn-p
:accessor
)))))))
2088 ;;; It's easier for the compiler to recognize the output of M-L-F-S-S
2089 ;;; without extraneous QUOTE forms, so we define some trivial wrapper macros.
2090 (defmacro new-instance
(type) `(allocate-instance (find-class ',type
)))
2091 (defmacro sb
!pcl
::set-slots
(instance name-list
&rest values
)
2092 `(sb!pcl
::%set-slots
,instance
',name-list
,@values
))
2094 ;;; We require that MAKE-LOAD-FORM-SAVING-SLOTS produce deterministic output
2095 ;;; and that its output take a particular recognizable form so that it can
2096 ;;; be optimized into a sequence of fasl ops. MAKE-LOAD-FORM no longer returns
2097 ;;; a magic keyword except for the special case of :IGNORE-IT.
2098 ;;; The cross-compiler depends critically on optimizing the resulting sexprs
2099 ;;; so that the host can load cold objects, which it could not do
2100 ;;; if constructed by machine code for the target.
2101 ;;; This ends up being a performance win for the target system as well.
2103 (labels ((dsd-primitive-accessor (dsd &aux
(rsd (dsd-raw-slot-data dsd
)))
2104 (if rsd
(raw-slot-data-accessor-name rsd
) '%instance-ref
))
2106 (cond ((listp val
) val
)
2107 ((symbolp val
) (not (or (eq val t
) (keywordp val
))))
2109 ;; Return T if (but not only-if) INITS came from M-L-F-S-S.
2110 (canonical-p (inits dsds object
&aux reader
)
2111 (dolist (dsd dsds
(null inits
))
2112 (declare (type defstruct-slot-description dsd
))
2113 (if (and (listp inits
)
2114 (let ((place (pop inits
)))
2116 (eq (setq reader
(dsd-primitive-accessor dsd
))
2118 (listp place
) (eq object
(pop place
))
2120 (eql (dsd-index dsd
) (car place
))))
2121 (let ((init (and (listp inits
) (car inits
)))
2122 (val (funcall reader object
(dsd-index dsd
))))
2124 (and (typep init
'(cons (eql quote
)))
2125 (singleton-p (cdr init
))
2126 (eq val
(cadr init
)))
2127 (and inits
(eql val init
)))))
2131 ;; It is possible to produce instances of structure-object which violate
2132 ;; the assumption throughout the compiler that slot readers are safe
2133 ;; unless dictated otherwise by the SAFE-P flag in the DSD.
2134 ;; * (defstruct S a (b (error "Must supply me") :type symbol))
2135 ;; * (defmethod make-load-form ((x S) &optional e) (m-l-f-s-s x :slot-names '(a)))
2136 ;; After these definitions, a dumped S will have 0 in slot B.
2138 (defun sb!xc
:make-load-form-saving-slots
(object &key
(slot-names nil slot-names-p
)
2140 (declare (ignore environment
))
2141 ;; If TYPE-OF isn't a symbol, the creation form probably can't be compiled
2142 ;; unless there is a MAKE-LOAD-FORM on the class without a proper-name.
2143 ;; This is better than returning a creation form that produces
2144 ;; something completely different.
2145 (values (let ((type (type-of object
)))
2146 `(,(if (symbolp type
) 'new-instance
'allocate-instance
) ,type
))
2147 (if (typep object
'structure-object
)
2150 (declare (type defstruct-slot-description dsd
))
2151 (when (or (not slot-names-p
)
2152 (memq (dsd-name dsd
) slot-names
))
2153 (let* ((acc (dsd-primitive-accessor dsd
))
2154 (ind (dsd-index dsd
))
2155 (val (funcall acc object ind
)))
2156 (list `(,acc
,object
,ind
)
2157 (if (quote-p val
) `',val val
)))))
2158 (dd-slots (layout-info (%instance-layout object
)))))
2160 (loop for slot in
(sb!mop
:class-slots
(class-of object
))
2161 for name
= (sb!mop
:slot-definition-name slot
)
2162 when
(if slot-names-p
2163 (memq name slot-names
)
2164 (eq (sb!mop
:slot-definition-allocation slot
) :instance
))
2165 collect name into names
2167 collect
(if (slot-boundp object name
)
2168 (let ((val (slot-value object name
)))
2169 (if (quote-p val
) `',val val
))
2170 'sb
!pcl
:+slot-unbound
+) into vals
2171 finally
(return `(sb!pcl
::set-slots
,object
,names
,@vals
))))))
2173 ;; Call MAKE-LOAD-FORM inside a condition handler in case the method fails.
2174 ; If the resulting CREATION-FORM and INIT-FORM are equivalent to those
2175 ;; returned from MAKE-LOAD-FORM-SAVING-SLOTS, return 'SB-FASL::FOP-STRUCT.
2176 ;; If the object can be ignored, return :IGNORE-IT and NIL.
2177 (defun sb!c
::%make-load-form
(constant)
2178 (multiple-value-bind (creation-form init-form
)
2179 (handler-case (sb!xc
:make-load-form constant
(make-null-lexenv))
2180 (error (condition) (sb!c
:compiler-error condition
)))
2181 (cond ((eq creation-form
:ignore-it
) (values :ignore-it nil
))
2182 ((and (listp creation-form
)
2183 (typep constant
'structure-object
)
2184 (typep creation-form
2185 '(cons (eql new-instance
) (cons symbol null
)))
2186 (eq (second creation-form
) (type-of constant
))
2187 (typep init-form
'(cons (eql setf
)))
2188 (canonical-p (cdr init-form
)
2189 (dd-slots (layout-info (%instance-layout constant
)))
2191 (values 'sb
!fasl
::fop-struct nil
))
2193 (values creation-form init-form
))))))
2195 (/show0
"code/defstruct.lisp end of file")