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