Add some bits to LAYOUT
[sbcl.git] / src / code / defstruct.lisp
blob7fd53389a2a4a0eb2d905eaeb127288773a632b5
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
5 ;;;; more information.
6 ;;;;
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")
17 ;;;; getting LAYOUTs
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)))
23 (cond ((not res)
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)
29 res))))
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
42 ;; so horribly.
43 `(let* ((cell (load-time-value (list nil)))
44 (fun (car cell)))
45 (if (functionp fun)
46 (funcall fun ,@slot-vars)
47 (funcall (setf (car cell)
48 (%make-structure-instance-allocator ,dd ,slot-specs))
49 ,@slot-vars)))))
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))))
55 (values (compile nil
56 `(lambda (,@vars)
57 (%make-structure-instance-macro ,dd ',slot-specs ,@vars))))))
59 (defun %make-funcallable-structure-instance-allocator (dd slot-specs)
60 (when 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")))
65 (values
66 (compile nil `(lambda ()
67 (let ((,nobject (%make-funcallable-instance ,length)))
68 (setf (%funcallable-instance-layout ,nobject)
69 (%delayed-get-compiler-layout ,name))
70 ,nobject))))))
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)))
80 (cond (layout
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))
86 `,layout)
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
95 (sb!c:compiler-notify
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))
102 ,layout))))))
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))
132 (:conc-name dsd-)
133 (:copier nil)
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
160 dsd-safe-p
161 ; dsd-read-only ; compilation order problem
162 ; dsd-index
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)))
210 (and rsd-index
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))
214 (t)))
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)
221 (list 'list)
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)
240 forms
241 `(eval ',forms))))
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)
273 (binding*
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
279 (nconc
280 (when keyword-constructors
281 (let ((primary (caar keyword-constructors)))
282 (cons
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)
291 `(defun ,(car ctor)
292 ,@(structure-ctor-lambda-parts dd (cdr ctor))))
293 boa-constructors)))
294 (name (dd-name dd))
295 (print-method
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.
305 (cond ((not fname)
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.
315 (values
316 (if (dd-class-p dd)
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
332 ,name
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
342 ,@print-method
343 ;; Various other operations only make sense on the target SBCL.
344 (%target-defstruct ',dd))))
345 ;; Not DD-CLASS-P
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
357 ,@(when (dd-doc dd)
358 `((setf (fdocumentation ',(dd-name dd) 'structure)
359 ',(dd-doc dd))))))))
360 name)))
362 #+sb-xc-host
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)))
369 #+sb-xc
370 (sb!xc:defmacro defstruct (name-and-options &rest slot-descriptions
371 &environment env)
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):
380 (:CONSTRUCTOR Name)
381 (:PREDICATE Name)
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.
392 Slot options:
394 :TYPE Type-Spec
395 Asserts that the value of this slot is always of the specified type.
397 :READ-ONLY {T | NIL}
398 If true, no setter function is defined for this slot."
399 (multiple-value-bind (forms name)
400 (!expander-for-defstruct
401 (etypecase env
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)
406 (null t))
407 name-and-options slot-descriptions :target)
408 `(progn ,@forms ',name)))
410 #+sb-xc-host
411 (defmacro sb!xc:defstruct (name-and-options &rest slot-descriptions)
412 "Cause information about a target structure to be built into the
413 cross-compiler."
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
420 ;;; accessor.
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
425 ;;; typed DEFSTRUCT.
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
430 (when predicate-name
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)
436 ,(cond
437 ((subtypep ltype 'list)
438 `(do ((head (the ,ltype ,argname) (cdr head))
439 (i 0 (1+ i)))
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/."
448 ltype))))))))))
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)
461 (collect ((stuff))
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))
466 (new-value '(value))
467 (slot-type `(and ,(dsd-type slot)
468 ,(dd-element-type defstruct))))
469 (let ((inherited (accessor-inherited-data name defstruct)))
470 (cond
471 ((not inherited)
472 (stuff `(declaim (inline ,name ,@(unless (dsd-read-only slot)
473 `((setf ,name))))))
474 (stuff `(defun ,name (structure)
475 (declare (type ,ltype structure))
476 (the ,slot-type (elt structure ,index))))
477 (unless (dsd-read-only slot)
478 (stuff
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))))))))
486 (stuff)))
488 ;;;; parsing
490 ;;; CLHS says that
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
510 :copier ; "
511 :predicate ; "
512 :print-function ; "
513 :print-object) ; "
514 #'equalp)
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+))
520 (args (rest option))
521 (arg-p (consp args))
522 (arg (if arg-p (car args)))
523 (name (dd-name dd)))
524 (declare (type (unsigned-byte 9) seen-options)) ; mask over DD-OPTION-NAMES
525 (when bit
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
534 (unless winp
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)))))
539 (case keyword
540 (:conc-name
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
550 (setf lambda-list
551 (cond ((not cname)
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.
559 (when ll-supplied-p
560 (style-warn "~S does not define a constructor" option)))
561 ((not ll-supplied-p) :default)
563 (multiple-value-call
564 (lambda (&rest x)
565 (declare (dynamic-extent x))
566 (subseq x 0 ; remove trailing NILs
567 (1+ (position-if #'identity x :from-end t))))
568 (parse-lambda-list
569 lambda-list
570 :accept (lambda-list-keyword-mask
571 '(&optional &rest &key &allow-other-keys &aux))
572 :silent t))))
573 (dd-constructors dd) ; preserve order, just because
574 (nconc (dd-constructors dd) (list (cons cname lambda-list))))))
575 (:copier
576 (setf (dd-copier-name dd) (if arg-p arg (symbolicate "COPY-" name))))
577 (:predicate
578 (setf (dd-predicate-name dd) (if arg-p arg (symbolicate name "-P"))))
579 (:include
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))
586 (:type
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))))
594 (:named
595 (error "The DEFSTRUCT option :NAMED takes no arguments."))
596 (:initial-offset
597 (setf (dd-offset dd) arg)) ; FIXME: disallow (:INITIAL-OFFSET NIL)
598 (:pure
599 (setf (dd-pure dd) arg))
601 (error "unknown DEFSTRUCT option:~% ~S" option)))
602 seen-options))
604 ;;; Parse OPTIONS into the given DD.
605 (defun parse-defstruct-options (options dd)
606 (let ((seen-options 0)
607 (named-p nil))
608 (dolist (option options)
609 (if (eq option :named)
610 (setf named-p t (dd-named dd) t)
611 (setq seen-options
612 (parse-1-dd-option
613 (cond ((consp option) option)
614 ((member option
615 '(:conc-name :constructor :copier :predicate))
616 (list option))
618 ;; FIXME: ugly message (defstruct (s :include) a)
619 ;; saying "unrecognized" when it means "bad syntax"
620 (error "unrecognized DEFSTRUCT option: ~S" option)))
621 dd seen-options))))
622 (case (dd-type dd)
623 (structure
624 (when (dd-offset dd)
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.
637 (if named-p
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))
651 (when named-p
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)
666 (if no-constructors
667 (progn
668 (when (or (keyword-ctors) (boa-ctors))
669 (error "(:CONSTRUCTOR NIL) combined with other :CONSTRUCTORs"))
670 nil)
671 (append (or (keyword-ctors)
672 (unless (boa-ctors)
673 `((,(symbolicate "MAKE-" name) . :default))))
674 (boa-ctors))))))
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)))))
686 seen-options))
688 ;;; Given name and options and slot descriptions (and possibly doc
689 ;;; string at the head of slot descriptions) return a DD holding that
690 ;;; info.
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)))
702 (let* ((inherits
703 (if (dd-class-p dd)
704 #+sb-xc-host (!inherits-for-structure dd)
705 #-sb-xc-host
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)))))
710 (proto-classoid
711 (if (dd-class-p dd)
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)
716 classoid))))
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))))
726 (if (dd-class-p dd)
727 (progn
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))
733 (parse-slots)))
734 (parse-slots)))
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)
744 rsd-index index)
745 #-sb-xc-host (declare (muffle-conditions style-warning))
746 (multiple-value-bind (name default default-p type type-p read-only ro-p)
747 (typecase spec
748 (symbol
749 (typecase spec
750 ((or null (member :conc-name :constructor :copier :predicate :named))
751 (warn "slot name of ~S indicates probable syntax error in DEFSTRUCT" spec))
752 (keyword
753 (style-warn "slot name of ~S indicates possible syntax error in DEFSTRUCT" spec)))
754 spec)
755 (cons
756 (destructuring-bind
757 (name &optional (default nil default-p)
758 &key (type nil type-p) (read-only nil ro-p))
759 spec
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.
767 (typecase name
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
773 read-only ro-p)))
774 (t (error 'simple-program-error
775 :format-control "in DEFSTRUCT, ~S is not a legal slot ~
776 description."
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)
788 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).
798 (style-warn
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.~@:>"
804 accessor-name)
805 (setf (dd-predicate-name defstruct) nil))
806 ;; FIXME: It would be good to check for name collisions here, but
807 ;; the easy check,
808 ;;x#-sb-xc-host
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)))))
826 (cond (included-slot
827 (cond ((not ro-p)
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.~:@>"
832 name)))
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))
837 (when (and safe-p
838 (not (equal type (dsd-type included-slot)))
839 (not (sb!xc:subtypep (dsd-type included-slot) type)))
840 (setf safe-p nil)))
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)))
845 (let ((n-words
846 (if rsd-index
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))
854 1)))
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))
869 name)))
870 (sixth ll-parts))))
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)
882 default)))
883 (setf (dd-slots defstruct) (nconc (dd-slots defstruct) (list dsd)))
884 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
896 ;; FIXNUM-CERTAIN?.)
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))
902 (return i)))))))
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))
913 (included-structure
914 (if (dd-class-p 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)"
933 included-name)))))
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))))
950 modified-slots))
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
956 ;; from a literal.
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)))
966 :test #'string=)
967 `(,included-name))))
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
975 ;; conflict.
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)))
982 ;; XXX: notify?
983 )))))))
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))
994 (super
995 (if include
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)
1001 ((ansi-stream)
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)
1010 (vector 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)
1017 (vector super
1018 (classoid-layout (find-classoid 'string-stream)))))
1019 (t (concatenate 'simple-vector
1020 (layout-inherits super)
1021 (vector 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)
1056 (list 'nth)
1057 (vector 'aref)))
1058 (index (dsd-index dsd))
1059 (rsd (dsd-raw-slot-data dsd)))
1060 (cond (rsd
1061 (list (raw-slot-data-accessor-name rsd) instance index))
1062 ((eq ref 'nth)
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.
1078 (place
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)))
1095 ,place)))
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)
1101 newval
1102 `(the* (,type-spec :context
1103 (:struct ,(dd-name dd) . ,(dsd-name dsd)))
1104 ,newval))))
1105 (ecase function
1106 (:setf
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))))
1110 (:write
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)))
1144 (when subclasses-p
1145 (let ((subclasses (classoid-subclasses classoid)))
1146 (when subclasses
1147 (collect ((subs))
1148 (dohash ((classoid layout)
1149 subclasses
1150 :locked t)
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?
1156 (when (subs)
1157 (warn "undeclaring functions for old subclasses ~
1158 of ~S:~% ~S"
1159 (classoid-name classoid)
1160 (subs))))))))
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
1165 &optional
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
1175 ;; assistance here)
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
1182 inherits
1183 (if clayout-p
1184 "The most recently compiled"
1185 "The current")
1186 "the most recently loaded"
1187 :compiler-layout clayout))
1188 (cond (old-layout
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.~:@>"
1197 classoid))
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))
1209 (values))
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)))))
1234 (fnames))
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.
1256 (when accessor-name
1257 (let ((inherited (accessor-inherited-data accessor-name dd)))
1258 (cond
1259 ((not inherited)
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)
1265 slot-key)
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 ~
1273 instead).~:@>"
1274 accessor-name
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)))
1300 (collect ((moved)
1301 (retyped))
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))
1306 (retyped name))
1307 (unless (and (= (dsd-index os) (dsd-index ns))
1308 (eq (dsd-raw-type os) (dsd-raw-type ns)))
1309 (moved name))))
1310 (values (moved)
1311 (retyped)
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)
1319 (ignore classoid))
1320 (let ((name (dd-name new)))
1321 (multiple-value-bind (moved retyped deleted) (compare-slots old new)
1322 (when (or moved retyped deleted)
1323 (warn
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)
1330 t))))
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
1343 (return nil)))))
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
1348 ;;; be used.
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)))
1353 (restart-case
1354 (error "~@<attempt to redefine the ~S class ~S incompatibly with the current definition~:@>"
1355 'structure-object
1356 name)
1357 (continue ()
1358 :report (lambda (s)
1359 (format s
1360 "~@<Use the new definition of ~S, invalidating ~
1361 already-loaded code and instances.~@:>"
1362 name))
1363 (register-layout new-layout))
1364 (recklessly-continue ()
1365 :test (lambda (c)
1366 (declare (ignore c))
1367 (mutable-layout-p old-layout new-layout))
1368 :report (lambda (s)
1369 (format s
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 ~
1373 instances.~@:>"
1374 name))
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
1378 :invalidate nil
1379 :destruct-layout old-layout))))
1380 (values))
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))
1410 (eql sign-ext -1))
1411 (return-from dd-bitmap sign-ext)))))
1412 bitmap))
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)
1431 (lambda (x)
1432 (sb!xc:typep x 'structure-classoid))
1433 (lambda (x)
1434 (sb!xc:typep x (classoid-name (find-classoid class)))))
1435 (fdefinition constructor)))
1436 (setf (classoid-direct-superclasses classoid)
1437 (case (dd-name info)
1438 ((ansi-stream
1439 fd-stream
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+))
1449 (new-layout
1450 (when (or (not old-layout) *type-system-initialized*)
1451 (make-layout :classoid classoid
1452 :%flags flags
1453 :inherits inherits
1454 :depthoid (length inherits)
1455 :length (dd-length info)
1456 :info info
1457 :bitmap (dd-bitmap info)))))
1458 (cond
1459 ((not old-layout)
1460 (values classoid new-layout nil))
1461 ((not new-layout)
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
1473 old-layout
1474 new-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)))
1482 (if old-info
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)))
1488 (progn
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)
1497 (collect ((res))
1498 (let ((infos ()))
1499 (do ((info defstruct
1500 (typed-structure-info-or-lose (first (dd-include info)))))
1501 ((not (dd-include info))
1502 (push info infos))
1503 (push info infos))
1505 (let ((i 0))
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)))))
1512 (res)))
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)
1545 (slot-specs spec)))
1547 (slot-specs spec)
1548 (slot-values value))))
1549 dd-slots values)
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)
1559 (slot-specs spec)))
1560 ((eq raw-type t)
1561 (slot-specs spec)
1562 (slot-values value))
1564 (raw-slots dsd)
1565 (raw-values value))))
1566 dd-slots values)
1567 (let ((instance-form
1568 `(%make-structure-instance-macro ,dd
1569 ',(slot-specs) ,@(slot-values))))
1570 (if (raw-slots)
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))
1579 ,temp))
1580 instance-form)))))
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))
1588 (values 'vector 0))
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)))
1596 (if operator
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)))
1601 (dolist (x names)
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)))
1610 slots values)
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)))
1616 names)
1617 ,@(mapcan (lambda (dsd val)
1618 (unless (eq val '.do-not-initialize-slot.)
1619 `((setf (aref ,temp ,(dsd-index dsd)) ,val))))
1620 slots values)
1621 ,temp))))))
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)))))
1638 `(function
1639 ,(if (eq args :default)
1640 `(&key ,@(mapcar (lambda (dsd)
1641 `(,(keywordicate (dsd-name dsd))
1642 ,(elt-type-intersect dsd)))
1643 (dd-slots dd)))
1644 (destructuring-bind (llks &optional req opt rest keys aux) args
1645 (let ((aux (mapcar (lambda (var) (if (listp var) (car var) var))
1646 aux)))
1647 (flet ((get-arg-type (name)
1648 (let ((slot (unless (member name aux :test #'string=)
1649 (find name (dd-slots dd) :key #'dsd-name
1650 :test #'string=))))
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))))
1654 (make-lambda-list
1655 llks nil (mapcar #'get-arg-type req)
1656 (mapcar (lambda (arg)
1657 (get-arg-type (parse-optional-arg-spec arg)))
1658 opt)
1659 (if rest (list t))
1660 (mapcar (lambda (arg)
1661 (multiple-value-bind (key var) (parse-key-arg-spec arg)
1662 `(,key ,(get-arg-type var))))
1663 keys))))))
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))))
1667 &optional))))
1669 (defun struct-ctor-ftype (dd name)
1670 (let ((ctor (assq name (dd-constructors dd))))
1671 (aver ctor)
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))
1680 (t info))
1681 foundp)))
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))))
1695 (dd-slots dd))))
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))
1702 (var (cadar arg)))
1703 (if (eq type t)
1705 `(the* (,type :context
1706 (:struct ,(dd-name dd) . ,(dsd-name dsd)))
1707 ,var))))
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
1711 (aux-vars)
1712 (skipped-vars))
1713 (dolist (binding aux)
1714 (let ((name (if (listp binding) (car binding) binding)))
1715 (aux-vars name)
1716 (unless (typep binding '(cons t cons))
1717 (skipped-vars name))))
1718 (macrolet ((rewrite (input key parse)
1719 `(mapcar
1720 (lambda (arg)
1721 (multiple-value-bind (,@key var def sup-p) (,parse arg)
1722 (declare (ignore ,@key def))
1723 (rewrite-1 arg var sup-p)))
1724 ,input)))
1725 (flet ((rewrite-1 (arg var sup-p-var)
1726 (vars 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))
1755 ,(funcall
1756 creator dd
1757 (mapcar
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)))))
1768 (dd-slots dd)))))))
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
1782 ;;;;
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.
1793 ;;;;
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
1800 ;;;;
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
1817 slot-names)
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.
1828 (case dd-type
1829 ;; We don't support inheritance of alternate metaclass stuff,
1830 ;; and it's not a general-purpose facility, so sanity check our
1831 ;; own code.
1832 (structure
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
1838 metaclass-name
1839 metaclass-constructor)
1840 (dd-slots dd)
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))
1844 nil t t nil)
1845 nil))
1846 slot-names)
1847 (dd-length dd) slot-index
1848 (dd-type dd) dd-type)
1849 dd))
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
1858 #+sb-xc-host
1859 (defmacro !defstruct-with-alternate-metaclass
1860 (class-name &key
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))
1871 boa-constructor
1872 superclass-name
1873 metaclass-name
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
1884 :dd-type dd-type)))
1885 `(progn
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
1891 (class-name &key
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))
1902 boa-constructor
1903 superclass-name
1904 metaclass-name
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
1914 :dd-type dd-type))
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)
1921 (ecase dd-type
1922 (structure
1923 (values `(%make-structure-instance-macro ,dd nil)
1924 '%instance-ref))
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)
1933 ,object-gensym)
1934 '%funcallable-instance-info)))
1935 `(progn
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
1947 ,(dsd-index dsd))))
1948 dd-slots)
1949 (declaim (inline ,@(mapcar (lambda (dsd)
1950 `(setf ,(dsd-accessor-name dsd)))
1951 dd-slots)))
1952 ,@(mapcar (lambda (dsd)
1953 `(defun (setf ,(dsd-accessor-name dsd)) (,new-value-gensym
1954 ,object-gensym)
1955 ,@(when runtime-type-checks-p
1956 `((declare (type ,class-name ,object-gensym))))
1957 (setf (,raw-reffer-operator ,object-gensym
1958 ,(dsd-index dsd))
1959 ,new-value-gensym)))
1960 dd-slots)
1962 ;; constructor
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)
1970 ,slot-name)))
1971 slot-names)
1972 ,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)))
1990 (setf
1991 (dd-slots dd) nil
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))
1999 (info (and classoid
2000 (layout-info (classoid-layout classoid)))))
2001 (cond ((defstruct-description-p info)
2002 info)
2003 (errorp
2004 (error "No DEFSTRUCT-DESCRIPTION for ~S." name)))))
2006 (defun structure-instance-accessor-p (name)
2007 (let ((info (info :function :source-transform name)))
2008 (and (listp info)
2009 (defstruct-slot-description-p (cdr info))
2010 info)))
2012 (defun dd-default-constructor (dd)
2013 (let ((ctor (first (dd-constructors dd))))
2014 (when (typep ctor '(cons t (eql :default)))
2015 (car ctor))))
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.
2021 #+sb-xc-host
2022 (progn
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))
2067 (form (car body)))
2068 (when (consp info)
2069 (when (and (eq (cdr info) :predicate)
2070 (equal lambda-list '(object))
2071 (typep form
2072 '(cons (eql typep)
2073 (cons (eql object)
2074 (cons (cons (eql quote) (cons t null))
2075 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)
2081 (if (consp name)
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))
2105 (quote-p (val)
2106 (cond ((listp val) val)
2107 ((symbolp val) (not (or (eq val t) (keywordp val))))
2108 (t nil)))
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)))
2115 (and (listp place)
2116 (eq (setq reader (dsd-primitive-accessor dsd))
2117 (pop place))
2118 (listp place) (eq object (pop place))
2119 (singleton-p place)
2120 (eql (dsd-index dsd) (car place))))
2121 (let ((init (and (listp inits) (car inits)))
2122 (val (funcall reader object (dsd-index dsd))))
2123 (if (quote-p val)
2124 (and (typep init '(cons (eql quote)))
2125 (singleton-p (cdr init))
2126 (eq val (cadr init)))
2127 (and inits (eql val init)))))
2128 (pop inits)
2129 (return nil)))))
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)
2139 environment)
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)
2148 `(setf ,@(mapcan
2149 (lambda (dsd)
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)))))
2159 #-sb-xc-host
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)))
2190 constant))
2191 (values 'sb!fasl::fop-struct nil))
2193 (values creation-form init-form))))))
2195 (/show0 "code/defstruct.lisp end of file")