gencgc: More precise conservatism for pointers to boxed pages.
[sbcl.git] / src / pcl / wrapper.lisp
index 909eee8..9cd4e01 100644 (file)
@@ -34,7 +34,7 @@
 ;;; This is called in BRAID when we are making wrappers for classes
 ;;; whose slots are not initialized yet, and which may be built-in
 ;;; classes. We pass in the class name in addition to the class.
-(defun boot-make-wrapper (length name &optional class)
+(defun !boot-make-wrapper (length name &optional class)
   (let ((found (find-classoid name nil)))
     (cond
      (found
 (declaim (inline wrapper-class*))
 (defun wrapper-class* (wrapper)
   (or (wrapper-class wrapper)
-      (ensure-non-standard-class
-       (classoid-name (layout-classoid wrapper)))))
+      (let ((classoid (layout-classoid wrapper)))
+        (ensure-non-standard-class
+         (classoid-name classoid)
+         classoid))))
 
 ;;; The wrapper cache machinery provides general mechanism for
 ;;; trapping on the next access to any instance of a given class. This
 ;;; We only use this inside INVALIDATE-WRAPPER.
 (defvar *previous-nwrappers* (make-hash-table))
 
-;;; We always call this inside WITH-PCL-LOCK.
-(defun invalidate-wrapper (owrapper state nwrapper)
+(defun %invalidate-wrapper (owrapper state nwrapper)
   (aver (member state '(:flush :obsolete) :test #'eq))
   (let ((new-previous ()))
     ;; First off, a previous call to INVALIDATE-WRAPPER may have
 
     ;; FIXME: We are here inside PCL lock, but might someone be
     ;; accessing the wrapper at the same time from outside the lock?
-    ;; Can it matter that they get 0 from one slot and a valid value
-    ;; from another?
-    (dotimes (i layout-clos-hash-length)
-      (setf (layout-clos-hash owrapper i) 0))
+    (setf (layout-clos-hash owrapper) 0)
 
     ;; FIXME: We could save a whopping cons by using (STATE . WRAPPER)
     ;; instead
     (remhash owrapper *previous-nwrappers*)
     (setf (gethash nwrapper *previous-nwrappers*) new-previous)))
 
+;;; FIXME: This is not a good name: part of the contract here is that
+;;; we return the valid wrapper, which is not obvious from the name
+;;; (or the names of our callees.)
 (defun check-wrapper-validity (instance)
-  (let* ((owrapper (wrapper-of instance))
-         (state (layout-invalid owrapper)))
-    (aver (not (eq state :uninitialized)))
-    (etypecase state
-      (null owrapper)
-      ;; FIXME: I can't help thinking that, while this does cure the
-      ;; symptoms observed from some class redefinitions, this isn't
-      ;; the place to be doing this flushing.  Nevertheless...  --
-      ;; CSR, 2003-05-31
-      ;;
-      ;; CMUCL comment:
-      ;;    We assume in this case, that the :INVALID is from a
-      ;;    previous call to REGISTER-LAYOUT for a superclass of
-      ;;    INSTANCE's class.  See also the comment above
-      ;;    FORCE-CACHE-FLUSHES.  Paul Dietz has test cases for this.
-      ((member t)
-       (force-cache-flushes (class-of instance))
-       (check-wrapper-validity instance))
-      (cons
-       (ecase (car state)
-         (:flush
-          (flush-cache-trap owrapper (cadr state) instance))
-         (:obsolete
-          (obsolete-instance-trap owrapper (cadr state) instance)))))))
+  (with-world-lock ()
+    (let* ((owrapper (wrapper-of instance))
+           (state (layout-invalid owrapper)))
+      (aver (not (eq state :uninitialized)))
+      (cond ((not state)
+             owrapper)
+            ((not (layout-for-std-class-p owrapper))
+             ;; Obsolete structure trap.
+             (%obsolete-instance-trap owrapper nil instance))
+            ((eq t state)
+             ;; FIXME: I can't help thinking that, while this does cure
+             ;; the symptoms observed from some class redefinitions,
+             ;; this isn't the place to be doing this flushing.
+             ;; Nevertheless... -- CSR, 2003-05-31
+             ;;
+             ;; CMUCL comment:
+             ;;    We assume in this case, that the :INVALID is from a
+             ;;    previous call to REGISTER-LAYOUT for a superclass of
+             ;;    INSTANCE's class.  See also the comment above
+             ;;    FORCE-CACHE-FLUSHES.  Paul Dietz has test cases for this.
+             (let ((class (wrapper-class* owrapper)))
+               (%force-cache-flushes class)
+               ;; KLUDGE: avoid an infinite recursion, it's still better to
+               ;; bail out with an error for server softwares. see FIXME above.
+               ;; details: http://thread.gmane.org/gmane.lisp.steel-bank.devel/10175
+               ;;
+               ;; Error message here is trying to figure out a bit more about the
+               ;; situation, since we don't have anything approaching a test-case
+               ;; for the bug.
+               (let ((new-state (layout-invalid (wrapper-of instance))))
+                 (unless (neq t new-state)
+                   (cerror "Nevermind and recurse." 'bug
+                           :format-control "~@<~4IProblem forcing cache flushes. Please report ~
+                                               to sbcl-devel.~
+                                            ~% Owrapper: ~S~
+                                            ~% Wrapper-of: ~S~
+                                            ~% Class-wrapper: ~S~%~:@>"
+                           :format-arguments (mapcar (lambda (x)
+                                                       (cons x (layout-invalid x)))
+                                                     (list owrapper
+                                                           (wrapper-of instance)
+                                                           (class-wrapper class)))))))
+             (check-wrapper-validity instance))
+            ((consp state)
+             (ecase (car state)
+               (:flush
+                (let ((new (cadr state)))
+                  (cond ((std-instance-p instance)
+                         (setf (std-instance-wrapper instance) new))
+                        ((fsc-instance-p instance)
+                         (setf (fsc-instance-wrapper instance) new))
+                        (t
+                         (bug "unrecognized instance type")))))
+               (:obsolete
+                (%obsolete-instance-trap owrapper (cadr state) instance))))
+            (t
+             (bug "Invalid LAYOUT-INVALID: ~S" state))))))
 
 (declaim (inline check-obsolete-instance))
 (defun check-obsolete-instance (instance)
   (when (invalid-wrapper-p (layout-of instance))
     (check-wrapper-validity instance)))
+
+(defun valid-wrapper-of (instance)
+  (let ((wrapper (wrapper-of instance)))
+    (if (invalid-wrapper-p wrapper)
+        (check-wrapper-validity instance)
+        wrapper)))
 \f
 ;;;  NIL: means nothing so far, no actual arg info has NILs in the
-;;;  metatype
+;;;  metatype.
 ;;;
 ;;;  CLASS: seen all sorts of metaclasses (specifically, more than one
 ;;;  of the next 5 values) or else have seen something which doesn't
-;;;  fall into a single category (SLOT-INSTANCE, FORWARD).
+;;;  fall into a single category (SLOT-INSTANCE, FORWARD).  Also used
+;;;  when seen a non-standard specializer.
+;;;
+;;;  T: means everything so far is the class T.
+;;;
+;;;  The above three are the really important ones, as they affect how
+;;;  discriminating functions are computed.  There are some other
+;;;  possible metatypes:
+;;;
+;;;  * STANDARD-INSTANCE: seen only standard classes
+;;;  * BUILT-IN-INSTANCE: seen only built in classes
+;;;  * STRUCTURE-INSTANCE: seen only structure classes
+;;;  * CONDITION-INSTANCE: seen only condition classes
 ;;;
-;;;  T: means everything so far is the class T
-;;;  STANDARD-INSTANCE: seen only standard classes
-;;;  BUILT-IN-INSTANCE: seen only built in classes
-;;;  STRUCTURE-INSTANCE: seen only structure classes
-;;;  CONDITION-INSTANCE: seen only condition classes
+;;;  but these are largely unexploited as of 2007-05-10.  The
+;;;  distinction between STANDARD-INSTANCE and the others is used in
+;;;  emitting wrapper/slot-getting code in accessor discriminating
+;;;  functions (see EMIT-FETCH-WRAPPER and EMIT-READER/WRITER); it is
+;;;  possible that there was an intention to use these metatypes to
+;;;  specialize cache implementation or discrimination nets, but this
+;;;  has not occurred as yet.
 (defun raise-metatype (metatype new-specializer)
-  (let ((slot      (find-class 'slot-class))
-        (standard  (find-class 'standard-class))
-        (fsc       (find-class 'funcallable-standard-class))
-        (condition (find-class 'condition-class))
-        (structure (find-class 'structure-class))
-        (built-in  (find-class 'built-in-class))
-        (frc       (find-class 'forward-referenced-class)))
+  (let ((slot      *the-class-slot-class*)
+        (standard  *the-class-standard-class*)
+        (fsc       *the-class-funcallable-standard-class*)
+        (condition *the-class-condition-class*)
+        (structure *the-class-structure-class*)
+        (built-in  *the-class-built-in-class*)
+        (frc       *the-class-forward-referenced-class*))
     (flet ((specializer->metatype (x)
-             (let ((meta-specializer
-                     (if (eq *boot-state* 'complete)
-                         (class-of (specializer-class x))
-                         (class-of x))))
+             (let* ((specializer-class (if (eq **boot-state** 'complete)
+                                           (specializer-class-or-nil x)
+                                           x))
+                   (meta-specializer (class-of specializer-class)))
                (cond
                  ((eq x *the-class-t*) t)
+                 ((not specializer-class) 'non-standard)
                  ((*subtypep meta-specializer standard) 'standard-instance)
                  ((*subtypep meta-specializer fsc) 'standard-instance)
                  ((*subtypep meta-specializer condition) 'condition-instance)
       (let ((new-metatype (specializer->metatype new-specializer)))
         (cond ((eq new-metatype 'slot-instance) 'class)
               ((eq new-metatype 'forward) 'class)
+              ((eq new-metatype 'non-standard) 'class)
               ((null metatype) new-metatype)
               ((eq metatype new-metatype) new-metatype)
               (t 'class))))))