1 ;;;; Bits and pieces of the wrapper machninery. This used to live in cache.lisp,
2 ;;;; but doesn't really logically belong there.
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; This software is derived from software originally released by Xerox
8 ;;;; Corporation. Copyright and release statements follow. Later modifications
9 ;;;; to the software are in the public domain and are provided with
10 ;;;; absolutely no warranty. See the COPYING and CREDITS files for more
13 ;;;; copyright information from original PCL sources:
15 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
16 ;;;; All rights reserved.
18 ;;;; Use and copying of this software and preparation of derivative works based
19 ;;;; upon this software are permitted. Any distribution of this software or
20 ;;;; derivative works must comply with all applicable United States export
23 ;;;; This software is made available AS IS, and Xerox Corporation makes no
24 ;;;; warranty about the software, its performance or its conformity to any
29 (defmacro wrapper-class
(wrapper)
30 `(classoid-pcl-class (layout-classoid ,wrapper
)))
31 (defmacro wrapper-no-of-instance-slots
(wrapper)
32 `(layout-length ,wrapper
))
34 (declaim (inline make-wrapper-internal
))
35 (defun make-wrapper-internal (&key length classoid
)
36 (make-layout :length length
:classoid classoid
:invalid nil
39 ;;; This is called in BRAID when we are making wrappers for classes
40 ;;; whose slots are not initialized yet, and which may be built-in
41 ;;; classes. We pass in the class name in addition to the class.
42 (defun !boot-make-wrapper
(length name
&optional class
)
43 (let ((found (find-classoid name nil
)))
46 (unless (classoid-pcl-class found
)
47 (setf (classoid-pcl-class found
) class
))
48 (aver (eq (classoid-pcl-class found
) class
))
49 (let ((layout (classoid-layout found
)))
53 (make-wrapper-internal
55 :classoid
(make-standard-classoid
56 :name name
:pcl-class class
))))))
58 ;;; The following variable may be set to a STANDARD-CLASS that has
59 ;;; already been created by the lisp code and which is to be redefined
60 ;;; by PCL. This allows STANDARD-CLASSes to be defined and used for
61 ;;; type testing and dispatch before PCL is loaded.
62 (defvar *pcl-class-boot
* nil
)
64 ;;; In SBCL, as in CMU CL, the layouts (a.k.a wrappers) for built-in
65 ;;; and structure classes already exist when PCL is initialized, so we
66 ;;; don't necessarily always make a wrapper. Also, we help maintain
67 ;;; the mapping between CL:CLASS and SB-KERNEL:CLASSOID objects.
68 (defun make-wrapper (length class
)
69 (declare (notinline slot-value
))
71 ((or (typep class
'std-class
)
72 (typep class
'forward-referenced-class
))
73 (make-wrapper-internal
76 (let ((owrap (class-wrapper class
)))
78 (layout-classoid owrap
))
79 ((or (*subtypep
(class-of class
) *the-class-standard-class
*)
80 (*subtypep
(class-of class
) *the-class-funcallable-standard-class
*)
81 (typep class
'forward-referenced-class
))
82 (cond ((and *pcl-class-boot
*
83 (eq (slot-value class
'name
) *pcl-class-boot
*))
84 (let ((found (find-classoid
85 (slot-value class
'name
))))
86 (unless (classoid-pcl-class found
)
87 (setf (classoid-pcl-class found
) class
))
88 (aver (eq (classoid-pcl-class found
) class
))
91 (let ((name (slot-value class
'name
)))
92 (make-standard-classoid :pcl-class class
93 :name
(and (symbolp name
) name
))))))
95 (bug "Got to T branch in ~S" 'make-wrapper
))))))
97 (let* ((found (find-classoid (slot-value class
'name
)))
98 (layout (classoid-layout found
)))
99 (unless (classoid-pcl-class found
)
100 (setf (classoid-pcl-class found
) class
))
101 (aver (eq (classoid-pcl-class found
) class
))
105 (declaim (inline wrapper-class
*))
106 (defun wrapper-class* (wrapper)
107 (or (wrapper-class wrapper
)
108 ;; FIXME: this branch seems unreachable.
109 ;; It would be nice to eliminate WRAPPER-CLASS* if we can show that it
110 ;; is only a holdover from an earlier way of bootstrapping that resulted
111 ;; in the temporary absence of a PCL-CLASS for some non-standard-class.
112 ;; Certainly no test gets here [changing it to (BUG "got here") worked].
114 ;; (CLASSOID-PCL-CLASS (FIND-CLASSOID 'STANDARD-INSTANCE)) => NIL
115 ;; which can be resolved by just ensuring one time that it has a CLASS.
116 ;; And nothing else seems to be problematic.
117 (let ((classoid (layout-classoid wrapper
)))
118 (ensure-non-standard-class
119 (classoid-name classoid
)
122 ;;; The wrapper cache machinery provides general mechanism for
123 ;;; trapping on the next access to any instance of a given class. This
124 ;;; mechanism is used to implement the updating of instances when the
125 ;;; class is redefined (MAKE-INSTANCES-OBSOLETE). The same mechanism
126 ;;; is also used to update generic function caches when there is a
127 ;;; change to the superclasses of a class.
129 ;;; Basically, a given wrapper can be valid or invalid. If it is
130 ;;; invalid, it means that any attempt to do a wrapper cache lookup
131 ;;; using the wrapper should trap. Also, methods on
132 ;;; SLOT-VALUE-USING-CLASS check the wrapper validity as well. This is
133 ;;; done by calling CHECK-WRAPPER-VALIDITY.
135 (declaim (inline invalid-wrapper-p
))
136 (defun invalid-wrapper-p (wrapper)
137 (not (null (layout-invalid wrapper
))))
139 ;;; We only use this inside INVALIDATE-WRAPPER.
140 (defvar *previous-nwrappers
* (make-hash-table))
142 (defun %invalidate-wrapper
(owrapper state nwrapper
)
143 (aver (member state
'(:flush
:obsolete
) :test
#'eq
))
144 (let ((new-previous ()))
145 ;; First off, a previous call to INVALIDATE-WRAPPER may have
146 ;; recorded OWRAPPER as an NWRAPPER to update to. Since OWRAPPER
147 ;; is about to be invalid, it no longer makes sense to update to
150 ;; We go back and change the previously invalidated wrappers so
151 ;; that they will now update directly to NWRAPPER. This
152 ;; corresponds to a kind of transitivity of wrapper updates.
153 (dolist (previous (gethash owrapper
*previous-nwrappers
*))
154 (when (eq state
:obsolete
)
155 (setf (car previous
) :obsolete
))
156 (setf (cadr previous
) nwrapper
)
157 (push previous new-previous
))
159 ;; FIXME: We are here inside PCL lock, but might someone be
160 ;; accessing the wrapper at the same time from outside the lock?
161 (setf (layout-clos-hash owrapper
) 0)
163 ;; FIXME: We could save a whopping cons by using (STATE . WRAPPER)
165 (push (setf (layout-invalid owrapper
) (list state nwrapper
))
168 (remhash owrapper
*previous-nwrappers
*)
169 (setf (gethash nwrapper
*previous-nwrappers
*) new-previous
)))
171 ;;; FIXME: This is not a good name: part of the contract here is that
172 ;;; we return the valid wrapper, which is not obvious from the name
173 ;;; (or the names of our callees.)
174 (defun check-wrapper-validity (instance)
176 (let* ((owrapper (layout-of instance
))
177 (state (layout-invalid owrapper
)))
178 (aver (not (eq state
:uninitialized
)))
181 ((not (layout-for-std-class-p owrapper
))
182 ;; Obsolete structure trap.
183 (%obsolete-instance-trap owrapper nil instance
))
185 ;; FIXME: I can't help thinking that, while this does cure
186 ;; the symptoms observed from some class redefinitions,
187 ;; this isn't the place to be doing this flushing.
188 ;; Nevertheless... -- CSR, 2003-05-31
191 ;; We assume in this case, that the :INVALID is from a
192 ;; previous call to REGISTER-LAYOUT for a superclass of
193 ;; INSTANCE's class. See also the comment above
194 ;; FORCE-CACHE-FLUSHES. Paul Dietz has test cases for this.
195 (let ((class (wrapper-class* owrapper
)))
196 (%force-cache-flushes class
)
197 ;; KLUDGE: avoid an infinite recursion, it's still better to
198 ;; bail out with an error for server softwares. see FIXME above.
199 ;; details: http://thread.gmane.org/gmane.lisp.steel-bank.devel/10175
201 ;; Error message here is trying to figure out a bit more about the
202 ;; situation, since we don't have anything approaching a test-case
204 (let ((new-state (layout-invalid (layout-of instance
))))
205 (when (eq new-state t
)
206 (cerror "Nevermind and recurse." 'bug
207 :format-control
"~@<~4IProblem forcing cache flushes. Please report ~
211 ~% Class-wrapper: ~S~%~:@>"
212 :format-arguments
(mapcar (lambda (x)
213 (cons x
(layout-invalid x
)))
216 (class-wrapper class
)))))))
217 (check-wrapper-validity instance
))
221 (let ((new (cadr state
)))
222 (cond ((std-instance-p instance
)
223 (setf (std-instance-wrapper instance
) new
))
224 ((fsc-instance-p instance
)
225 (setf (fsc-instance-wrapper instance
) new
))
227 (bug "unrecognized instance type")))))
229 (%obsolete-instance-trap owrapper
(cadr state
) instance
))))))))
231 (declaim (inline check-obsolete-instance
))
232 (defun check-obsolete-instance (instance)
233 (when (invalid-wrapper-p (layout-of instance
))
234 (check-wrapper-validity instance
)))
236 (defun valid-wrapper-of (instance)
237 (let ((wrapper (layout-of instance
)))
238 (if (invalid-wrapper-p wrapper
)
239 (check-wrapper-validity instance
)
242 ;;; NIL: means nothing so far, no actual arg info has NILs in the
245 ;;; CLASS: seen all sorts of metaclasses (specifically, more than one
246 ;;; of the next 5 values) or else have seen something which doesn't
247 ;;; fall into a single category (SLOT-INSTANCE, FORWARD). Also used
248 ;;; when seen a non-standard specializer.
250 ;;; T: means everything so far is the class T.
252 ;;; The above three are the really important ones, as they affect how
253 ;;; discriminating functions are computed. There are some other
254 ;;; possible metatypes:
256 ;;; * STANDARD-INSTANCE: seen only standard classes
257 ;;; * BUILT-IN-INSTANCE: seen only built in classes
258 ;;; * STRUCTURE-INSTANCE: seen only structure classes
259 ;;; * CONDITION-INSTANCE: seen only condition classes
261 ;;; but these are largely unexploited as of 2007-05-10. The
262 ;;; distinction between STANDARD-INSTANCE and the others is used in
263 ;;; emitting wrapper/slot-getting code in accessor discriminating
264 ;;; functions (see EMIT-FETCH-WRAPPER and EMIT-READER/WRITER); it is
265 ;;; possible that there was an intention to use these metatypes to
266 ;;; specialize cache implementation or discrimination nets, but this
267 ;;; has not occurred as yet.
268 (defun raise-metatype (metatype new-specializer
)
269 (let ((slot *the-class-slot-class
*)
270 (standard *the-class-standard-class
*)
271 (fsc *the-class-funcallable-standard-class
*)
272 (condition *the-class-condition-class
*)
273 (structure *the-class-structure-class
*)
274 (system *the-class-system-class
*)
275 (frc *the-class-forward-referenced-class
*))
276 (flet ((specializer->metatype
(x)
277 (let* ((specializer-class (if (eq **boot-state
** 'complete
)
278 (specializer-class-or-nil x
)
280 (meta-specializer (class-of specializer-class
)))
282 ((eq x
*the-class-t
*) t
)
283 ((not specializer-class
) 'non-standard
)
284 ((*subtypep meta-specializer standard
) 'standard-instance
)
285 ((*subtypep meta-specializer fsc
) 'standard-instance
)
286 ((*subtypep meta-specializer condition
) 'condition-instance
)
287 ((*subtypep meta-specializer structure
) 'structure-instance
)
288 ((*subtypep meta-specializer system
) 'system-instance
)
289 ((*subtypep meta-specializer slot
) 'slot-instance
)
290 ((*subtypep meta-specializer frc
) 'forward
)
291 (t (error "~@<PCL cannot handle the specializer ~S ~
292 (meta-specializer ~S).~@:>"
293 new-specializer meta-specializer
))))))
294 ;; We implement the following table. The notation is
295 ;; that X and Y are distinct meta specializer names.
297 ;; NIL <anything> ===> <anything>
300 (let ((new-metatype (specializer->metatype new-specializer
)))
301 (cond ((eq new-metatype
'slot-instance
) 'class
)
302 ((eq new-metatype
'forward
) 'class
)
303 ((eq new-metatype
'non-standard
) 'class
)
304 ((null metatype
) new-metatype
)
305 ((eq metatype new-metatype
) new-metatype
)
308 (defmacro with-dfun-wrappers
((args metatypes
)
309 (dfun-wrappers invalid-wrapper-p
310 &optional wrappers classes types
)
311 invalid-arguments-form
313 `(let* ((args-tail ,args
) (,invalid-wrapper-p nil
) (invalid-arguments-p nil
)
314 (,dfun-wrappers nil
) (dfun-wrappers-tail nil
)
316 `((wrappers-rev nil
) (types-rev nil
) (classes-rev nil
))))
317 (dolist (mt ,metatypes
)
319 (setq invalid-arguments-p t
)
321 (let* ((arg (pop args-tail
))
324 `((class *the-class-t
*)
327 (setq wrapper
(layout-of arg
))
328 (when (invalid-wrapper-p wrapper
)
329 (setq ,invalid-wrapper-p t
)
330 (setq wrapper
(check-wrapper-validity arg
)))
331 (cond ((null ,dfun-wrappers
)
332 (setq ,dfun-wrappers wrapper
))
333 ((not (consp ,dfun-wrappers
))
334 (setq dfun-wrappers-tail
(list wrapper
))
335 (setq ,dfun-wrappers
(cons ,dfun-wrappers dfun-wrappers-tail
)))
337 (let ((new-dfun-wrappers-tail (list wrapper
)))
338 (setf (cdr dfun-wrappers-tail
) new-dfun-wrappers-tail
)
339 (setf dfun-wrappers-tail new-dfun-wrappers-tail
))))
341 `((setq class
(wrapper-class* wrapper
))
342 (setq type
`(class-eq ,class
)))))
344 `((push wrapper wrappers-rev
)
345 (push class classes-rev
)
346 (push type types-rev
)))))
347 (if invalid-arguments-p
348 ,invalid-arguments-form
349 (let* (,@(when wrappers
350 `((,wrappers
(nreverse wrappers-rev
))
351 (,classes
(nreverse classes-rev
))
352 (,types
(mapcar (lambda (class)