1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; This software is derived from the CMU CL system, which was
5 ;;;; written at Carnegie Mellon University and released into the
6 ;;;; public domain. The software is in the public domain and is
7 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
8 ;;;; files for more information.
10 (in-package "SB!KERNEL")
12 (/show0 "target-defstruct.lisp 12")
14 ;;;; structure frobbing primitives
16 (defun %make-instance (length)
18 "Allocate a new instance with LENGTH data slots."
19 (declare (type index length))
20 (%make-instance length))
22 (defun %instance-length (instance)
24 "Given an instance, return its length."
25 (declare (type instance instance))
26 (%instance-length instance))
28 (defun %instance-ref (instance index)
30 "Return the value from the INDEXth slot of INSTANCE. This is SETFable."
31 (%instance-ref instance index))
33 (defun %instance-set (instance index new-value)
35 "Set the INDEXth slot of INSTANCE to NEW-VALUE."
36 (setf (%instance-ref instance index) new-value))
38 (defun %raw-ref-single (vec index)
39 (declare (type index index))
40 (%raw-ref-single vec index))
42 (defun %raw-ref-double (vec index)
43 (declare (type index index))
44 (%raw-ref-double vec index))
47 (defun %raw-ref-long (vec index)
48 (declare (type index index))
49 (%raw-ref-long vec index))
51 (defun %raw-set-single (vec index val)
52 (declare (type index index))
53 (%raw-set-single vec index val))
55 (defun %raw-set-double (vec index val)
56 (declare (type index index))
57 (%raw-set-double vec index val))
60 (defun %raw-set-long (vec index val)
61 (declare (type index index))
62 (%raw-set-long vec index val))
64 (defun %raw-ref-complex-single (vec index)
65 (declare (type index index))
66 (%raw-ref-complex-single vec index))
68 (defun %raw-ref-complex-double (vec index)
69 (declare (type index index))
70 (%raw-ref-complex-double vec index))
73 (defun %raw-ref-complex-long (vec index)
74 (declare (type index index))
75 (%raw-ref-complex-long vec index))
77 (defun %raw-set-complex-single (vec index val)
78 (declare (type index index))
79 (%raw-set-complex-single vec index val))
81 (defun %raw-set-complex-double (vec index val)
82 (declare (type index index))
83 (%raw-set-complex-double vec index val))
86 (defun %raw-set-complex-long (vec index val)
87 (declare (type index index))
88 (%raw-set-complex-long vec index val))
90 (defun %instance-layout (instance)
91 (%instance-layout instance))
93 (defun %set-instance-layout (instance new-value)
94 (%set-instance-layout instance new-value))
96 (defun %make-funcallable-instance (len layout)
97 (%make-funcallable-instance len layout))
99 (defun funcallable-instance-p (x) (funcallable-instance-p x))
101 (defun %funcallable-instance-info (fin i)
102 (%funcallable-instance-info fin i))
104 (defun %set-funcallable-instance-info (fin i new-value)
105 (%set-funcallable-instance-info fin i new-value))
107 (defun funcallable-instance-function (fin)
108 (%funcallable-instance-lexenv fin))
110 ;;; The heart of the magic of funcallable instances ("FINs"). The
111 ;;; function for a FIN must be a magical INSTANCE-LAMBDA form. When
112 ;;; called (as with any other function), we grab the code pointer, and
113 ;;; call it, leaving the original function object in LEXENV (in case
114 ;;; it was a closure). If it is actually a FIN, then we need to do an
115 ;;; extra indirection with funcallable-instance-lexenv to get at any
116 ;;; closure environment. This extra indirection is set up when
117 ;;; accessing the closure environment of an INSTANCE-LAMBDA. Note that
118 ;;; the original FIN pointer is lost, so if the called function wants
119 ;;; to get at the original object to do some slot accesses, it must
120 ;;; close over the FIN object.
122 ;;; If we set the FIN function to be a FIN, we directly copy across
123 ;;; both the code pointer and the lexenv, since that code pointer (for
124 ;;; an instance-lambda) is expecting that lexenv to be accessed. This
125 ;;; effectively pre-flattens what would otherwise be a chain of
126 ;;; indirections. Lest this sound like an excessively obscure case,
127 ;;; note that it happens when PCL dispatch functions are
130 ;;; The only loss is that if someone accesses the
131 ;;; FUNCALLABLE-INSTANCE-FUNCTION, then won't get a FIN back. This
132 ;;; probably doesn't matter, since PCL only sets the FIN function. And
133 ;;; the only reason that interpreted functions are FINs instead of
134 ;;; bare closures is for debuggability.
135 (defun (setf funcallable-instance-function) (new-value fin)
136 (setf (%funcallable-instance-function fin)
137 (%closure-function new-value))
138 (setf (%funcallable-instance-lexenv fin)
139 (if (funcallable-instance-p new-value)
140 (%funcallable-instance-lexenv new-value)
143 ;;; Copy any old kind of structure.
144 (defun copy-structure (structure)
146 "Return a copy of STRUCTURE with the same (EQL) slot values."
147 (declare (type structure-object structure))
148 (let* ((len (%instance-length structure))
149 (res (%make-instance len))
150 (layout (%instance-layout structure)))
152 (declare (type index len))
153 (when (layout-invalid layout)
154 (error "attempt to copy an obsolete structure:~% ~S" structure))
156 ;; Copy ordinary slots.
158 (declare (type index i))
159 (setf (%instance-ref res i)
160 (%instance-ref structure i)))
163 (let ((raw-index (dd-raw-index (layout-info layout))))
165 (let* ((data (%instance-ref structure raw-index))
166 (raw-len (length data))
167 (new (make-array raw-len :element-type '(unsigned-byte 32))))
168 (declare (type (simple-array (unsigned-byte 32) (*)) data))
169 (setf (%instance-ref res raw-index) new)
171 (setf (aref new i) (aref data i))))))
175 ;;; default PRINT and MAKE-LOAD-FORM methods
177 (defun default-structure-print (structure stream depth)
178 (declare (ignore depth))
179 (if (funcallable-instance-p structure)
180 (print-unreadable-object (structure stream :identity t :type t))
181 (let* ((type (%instance-layout structure))
182 (name (sb!xc:class-name (layout-class type)))
183 (dd (layout-info type)))
185 (pprint-logical-block (stream nil :prefix "#S(" :suffix ")")
187 (let ((slots (dd-slots dd)))
189 (write-char #\space stream)
190 ;; CMU CL had (PPRINT-INDENT :BLOCK 2 STREAM) here,
191 ;; but I can't see why. -- WHN 20000205
192 (pprint-newline :linear stream)
195 (let ((slot (pop slots)))
196 (write-char #\: stream)
197 (output-symbol-name (dsd-%name slot) stream)
198 (write-char #\space stream)
199 (pprint-newline :miser stream)
200 (output-object (funcall (fdefinition (dsd-accessor slot))
205 (write-char #\space stream)
206 (pprint-newline :linear stream))))))
207 (descend-into (stream)
208 (write-string "#S(" stream)
210 (do ((index 0 (1+ index))
211 (slots (dd-slots dd) (cdr slots)))
213 (and (not *print-readably*)
215 (>= index *print-length*)))
217 (write-string ")" stream)
218 (write-string " ...)" stream)))
219 (declare (type index index))
220 (write-char #\space stream)
221 (write-char #\: stream)
222 (let ((slot (first slots)))
223 (output-symbol-name (dsd-%name slot) stream)
224 (write-char #\space stream)
225 (output-object (funcall (fdefinition (dsd-accessor slot))
228 (def!method print-object ((x structure-object) stream)
229 (default-structure-print x stream *current-level*))
231 (defun make-load-form-saving-slots (object &key slot-names environment)
232 (declare (ignore object environment))
234 (error "stub: MAKE-LOAD-FORM-SAVING-SLOTS :SLOT-NAMES not implemented") ; KLUDGE
235 :just-dump-it-normally))
237 ;;; Return true if OBJ is an object of the structure type
238 ;;; corresponding to LAYOUT. This is called by the accessor closures,
239 ;;; which have a handle on the type's layout.
241 ;;; FIXME: This is fairly big, so it should probably become
242 ;;; MAYBE-INLINE instead of INLINE. Or else we could fix things up so
243 ;;; that the things which call it are all closures, so that it's
244 ;;; expanded only in a small number of places.
245 #!-sb-fluid (declaim (inline typep-to-layout))
246 (defun typep-to-layout (obj layout)
247 (declare (type layout layout) (optimize (speed 3) (safety 0)))
248 (when (layout-invalid layout)
249 (error "An obsolete structure accessor function was called."))
250 ;; FIXME: CMU CL used (%INSTANCEP OBJ) here. Check that
251 ;; (TYPEP OBJ 'INSTANCE) is optimized to equally efficient code.
252 (and (typep obj 'instance)
253 (let (;; FIXME: Mightn't there be a slight efficiency improvement
254 ;; by delaying the binding of DEPTHOID 'til it's needed?
255 (depthoid (layout-depthoid layout))
256 (obj-layout (%instance-layout obj)))
257 (cond ((eq obj-layout layout)
259 ;; FIXME: Does the test for LAYOUT-INVALID really belong
260 ;; after the test for EQ LAYOUT? Either explain why this
261 ;; is, or change the order.
262 ((layout-invalid obj-layout)
263 (error 'layout-invalid
264 :expected-type (layout-class obj-layout)
267 (and (> (layout-depthoid obj-layout) depthoid)
268 (eq (svref (layout-inherits obj-layout) depthoid)
271 ;;;; implementing structure slot accessors as closures
273 ;;; In the normal case of structures that have a real type (i.e. no
274 ;;; :TYPE option was specified), we want to optimize things for space
275 ;;; as well as speed, since there can be thousands of defined slot
278 ;;; What we do is define the accessors and copier as closures over
279 ;;; general-case code. Since the compiler will normally open-code
280 ;;; accessors, the (minor) extra speed penalty for full calls is not a
283 ;;; KLUDGE: This is a minor headache at cold init time, since genesis
284 ;;; doesn't know how to create the closures in the cold image, so the
285 ;;; function definitions aren't done until the appropriate top level
286 ;;; forms are executed, so any forward references to structure slots
287 ;;; (which are compiled into full calls) fail. The headache can be
288 ;;; treated by using SB!XC:DEFSTRUCT on the relevant structure at
289 ;;; build-the-cross-compiler time, so that the compiler is born
290 ;;; knowing how to inline accesses to the relevant structure, so no
291 ;;; full calls are made. This can be achieved by calling
292 ;;; SB!XC:DEFSTRUCT directly, or by using DEF!STRUCT, which (among
293 ;;; other things) calls SB!XC:DEFSTRUCT for you.
295 ;;; Return closures to do slot access according to Layout and DSD. We check
296 ;;; types, then do the access. This is only used for normal slots, not raw
298 (defun structure-slot-getter (layout dsd)
299 (let ((class (layout-class layout)))
300 (if (typep class 'basic-structure-class)
301 #'(lambda (structure)
302 (declare (optimize (speed 3) (safety 0)))
303 (flet ((structure-test (structure)
304 (typep-to-layout structure layout)))
305 (unless (structure-test structure)
306 (error 'simple-type-error
308 ;; FIXME: :EXPECTED-TYPE should be something
309 ;; comprehensible to the user, not this. Perhaps we
310 ;; could work backwards from the LAYOUT-CLASS slot to
311 ;; find something. (Note that all four SIMPLE-TYPE-ERROR
312 ;; calls in this section have the same disease.)
313 :expected-type '(satisfies structure-test)
315 "Structure for accessor ~S is not a ~S:~% ~S"
317 (list (dsd-accessor dsd)
318 (sb!xc:class-name (layout-class layout))
320 (%instance-ref structure (dsd-index dsd)))
321 #'(lambda (structure)
322 (declare (optimize (speed 3) (safety 0)))
323 (unless (%typep structure class)
324 (error 'simple-type-error
326 :expected-type 'class
328 "The structure for accessor ~S is not a ~S:~% ~S"
330 (list (dsd-accessor dsd) class
332 (%instance-ref structure (dsd-index dsd))))))
333 (defun structure-slot-setter (layout dsd)
334 (let ((class (layout-class layout)))
335 (if (typep class 'basic-structure-class)
336 #'(lambda (new-value structure)
337 (declare (optimize (speed 3) (safety 0)))
338 (flet ((structure-test (structure)
339 (typep-to-layout structure layout))
340 (typep-test (new-value)
341 (%typep new-value (dsd-type dsd))))
342 (unless (structure-test structure)
343 (error 'simple-type-error
345 :expected-type '(satisfies structure-test)
347 "The structure for setter ~S is not a ~S:~% ~S"
349 (list `(setf ,(dsd-accessor dsd))
350 (sb!xc:class-name (layout-class layout))
352 (unless (typep-test new-value)
353 (error 'simple-type-error
355 :expected-type '(satisfies typep-test)
357 "The new value for setter ~S is not a ~S:~% ~S"
359 (list `(setf ,(dsd-accessor dsd))
362 (setf (%instance-ref structure (dsd-index dsd)) new-value))
363 #'(lambda (new-value structure)
364 (declare (optimize (speed 3) (safety 0)))
365 (flet ((structure-test (structure)
366 (sb!xc:typep structure class))
367 (typep-test (new-value)
368 (%typep new-value (dsd-type dsd))))
369 (unless (structure-test structure)
370 (error 'simple-type-error
372 :expected-type '(satisfies structure-test)
374 "The structure for setter ~S is not a ~S:~% ~S"
376 (list `(setf ,(dsd-accessor dsd))
377 (sb!xc:class-name class)
379 (unless (typep-test new-value)
380 (error 'simple-type-error
382 :expected-type '(satisfies typep-test)
384 "The new value for setter ~S is not a ~S:~% ~S"
386 (list `(setf ,(dsd-accessor dsd))
389 (setf (%instance-ref structure (dsd-index dsd)) new-value)))))
391 (/show0 "target-defstruct.lisp end of file")