X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fpcl%2Fstd-class.lisp;h=ab1406f027c53f7b703d72d81089b04a677b88e2;hb=8fe977ca5d0d068f2641dd06d3743a4c218d5cc1;hp=a602fe715eb83cf257aeafa8d35c6511417fb71d;hpb=a682f4c392bc874a6a898632889319ebdd8821fc;p=sbcl.git diff --git a/src/pcl/std-class.lisp b/src/pcl/std-class.lisp index a602fe7..ab1406f 100644 --- a/src/pcl/std-class.lisp +++ b/src/pcl/std-class.lisp @@ -99,16 +99,15 @@ type gf) (let* ((name (slot-value slotd 'name)) (class (slot-value slotd '%class)) - (old-slotd (find-slot-definition class name)) + (old-slotd (when (class-finalized-p class) + (find-slot-definition class name))) (old-std-p (and old-slotd (slot-accessor-std-p old-slotd 'all)))) (multiple-value-bind (function std-p) (if (eq *boot-state* 'complete) (get-accessor-method-function gf type class slotd) (get-optimized-std-accessor-method-function class slotd type)) (setf (slot-accessor-std-p slotd type) std-p) - (setf (slot-accessor-function slotd type) function)) - (when (and old-slotd (not (eq old-std-p (slot-accessor-std-p slotd 'all)))) - (push (cons class name) *pv-table-cache-update-info*)))) + (setf (slot-accessor-function slotd type) function)))) (defmethod slot-definition-allocation ((slotd structure-slot-definition)) :instance) @@ -151,7 +150,7 @@ ;;; here, the values are read by an automatically generated reader method. (defmethod add-direct-subclass ((class class) (subclass class)) (with-slots (direct-subclasses) class - (pushnew subclass direct-subclasses) + (pushnew subclass direct-subclasses :test #'eq) subclass)) (defmethod remove-direct-subclass ((class class) (subclass class)) (with-slots (direct-subclasses) class @@ -173,15 +172,40 @@ ;;; In each case, we maintain one value which is a cons. The car is the list ;;; methods. The cdr is a list of the generic functions. The cdr is always ;;; computed lazily. + +;;; This needs to be used recursively, in case a non-trivial user +;;; defined ADD/REMOVE-DIRECT-METHOD method ends up calling another +;;; function using the same lock. +(defvar *specializer-lock* (sb-thread::make-spinlock :name "Specializer lock")) + +(defmethod add-direct-method :around ((specializer specializer) method) + ;; All the actions done under this lock are done in an order + ;; that is safe to unwind at any point. + (sb-thread::with-recursive-spinlock (*specializer-lock*) + (call-next-method))) + +(defmethod remove-direct-method :around ((specializer specializer) method) + ;; All the actions done under this lock are done in an order + ;; that is safe to unwind at any point. + (sb-thread::with-recursive-spinlock (*specializer-lock*) + (call-next-method))) + (defmethod add-direct-method ((specializer class) (method method)) - (with-slots (direct-methods) specializer - (setf (car direct-methods) (adjoin method (car direct-methods)) ;PUSH - (cdr direct-methods) ())) + (let ((cell (slot-value specializer 'direct-methods))) + ;; We need to first smash the CDR, because a parallel read may + ;; be in progress, and because if an interrupt catches us we + ;; need to have a consistent state. + (setf (cdr cell) () + (car cell) (adjoin method (car cell) :test #'eq))) method) + (defmethod remove-direct-method ((specializer class) (method method)) - (with-slots (direct-methods) specializer - (setf (car direct-methods) (remove method (car direct-methods)) - (cdr direct-methods) ())) + (let ((cell (slot-value specializer 'direct-methods))) + ;; We need to first smash the CDR, because a parallel read may + ;; be in progress, and because if an interrupt catches us we + ;; need to have a consistent state. + (setf (cdr cell) () + (car cell) (remove method (car cell)))) method) (defmethod specializer-direct-methods ((specializer class)) @@ -189,20 +213,26 @@ (car direct-methods))) (defmethod specializer-direct-generic-functions ((specializer class)) - (with-slots (direct-methods) specializer - (or (cdr direct-methods) - (setf (cdr direct-methods) - (let (collect) - (dolist (m (car direct-methods)) - ;; the old PCL code used COLLECTING-ONCE which used - ;; #'EQ to check for newness - (pushnew (method-generic-function m) collect :test #'eq)) - (nreverse collect)))))) + (let ((cell (slot-value specializer 'direct-methods))) + ;; If an ADD/REMOVE-METHOD is in progress, no matter: either + ;; we behave as if we got just first or just after -- it's just + ;; for update that we need to lock. + (or (cdr cell) + (sb-thread::with-spinlock (*specializer-lock*) + (setf (cdr cell) + (let (collect) + (dolist (m (car cell)) + ;; the old PCL code used COLLECTING-ONCE which used + ;; #'EQ to check for newness + (pushnew (method-generic-function m) collect :test #'eq)) + (nreverse collect))))))) ;;; This hash table is used to store the direct methods and direct generic ;;; functions of EQL specializers. Each value in the table is the cons. -(defvar *eql-specializer-methods* (make-hash-table :test 'eql)) -(defvar *class-eq-specializer-methods* (make-hash-table :test 'eq)) +;;; +;;; These tables are shared between threads, so they need to be synchronized. +(defvar *eql-specializer-methods* (make-hash-table :test 'eql :synchronized t)) +(defvar *class-eq-specializer-methods* (make-hash-table :test 'eq :synchronized t)) (defmethod specializer-method-table ((specializer eql-specializer)) *eql-specializer-methods*) @@ -216,11 +246,13 @@ (table (specializer-method-table specializer)) (entry (gethash object table))) (unless entry - (setq entry - (setf (gethash object table) - (cons nil nil)))) - (setf (car entry) (adjoin method (car entry)) - (cdr entry) ()) + (setf entry + (setf (gethash object table) (cons nil nil)))) + ;; We need to first smash the CDR, because a parallel read may + ;; be in progress, and because if an interrupt catches us we + ;; need to have a consistent state. + (setf (cdr entry) () + (car entry) (adjoin method (car entry) :test #'eq)) method)) (defmethod remove-direct-method ((specializer specializer-with-object) @@ -228,8 +260,11 @@ (let* ((object (specializer-object specializer)) (entry (gethash object (specializer-method-table specializer)))) (when entry - (setf (car entry) (remove method (car entry)) - (cdr entry) ())) + ;; We need to first smash the CDR, because a parallel read may + ;; be in progress, and because if an interrupt catches us we + ;; need to have a consistent state. + (setf (cdr entry) () + (car entry) (remove method (car entry)))) method)) (defmethod specializer-direct-methods ((specializer specializer-with-object)) @@ -242,11 +277,12 @@ (entry (gethash object (specializer-method-table specializer)))) (when entry (or (cdr entry) - (setf (cdr entry) - (let (collect) - (dolist (m (car entry)) - (pushnew (method-generic-function m) collect :test #'eq)) - (nreverse collect))))))) + (sb-thread::with-spinlock (*specializer-lock*) + (setf (cdr entry) + (let (collect) + (dolist (m (car entry)) + (pushnew (method-generic-function m) collect :test #'eq)) + (nreverse collect)))))))) (defun map-specializers (function) (map-all-classes (lambda (class) @@ -356,7 +392,8 @@ ((class std-class) slot-names &key (direct-superclasses nil direct-superclasses-p) (direct-slots nil direct-slots-p) - (direct-default-initargs nil direct-default-initargs-p)) + (direct-default-initargs nil direct-default-initargs-p) + definition-source) (cond (direct-superclasses-p (setq direct-superclasses (or direct-superclasses @@ -395,7 +432,7 @@ (old (assoc name old-class-slot-cells))) (if (or (not old) (eq t slot-names) - (member name slot-names)) + (member name slot-names :test #'eq)) (let* ((initfunction (slot-definition-initfunction dslotd)) (value (if initfunction (funcall initfunction) @@ -408,7 +445,7 @@ ;; required by AMOP, "Reinitialization of Class Metaobjects" (finalize-inheritance class) (update-class class nil)) - (add-slot-accessors class direct-slots) + (add-slot-accessors class direct-slots definition-source) (make-preliminary-layout class)) (defmethod shared-initialize :after ((class forward-referenced-class) @@ -482,7 +519,7 @@ (defmethod shared-initialize :after ((class condition-class) slot-names &key direct-slots direct-superclasses) (declare (ignore slot-names)) - (let ((classoid (find-classoid (class-name class)))) + (let ((classoid (find-classoid (slot-value class 'name)))) (with-slots (wrapper %class-precedence-list cpl-available-p prototype (direct-supers direct-superclasses)) class @@ -496,7 +533,9 @@ (setq %class-precedence-list (compute-class-precedence-list class)) (setq cpl-available-p t) (add-direct-subclasses class direct-superclasses) - (setf (slot-value class 'slots) (compute-slots class)))) + (let ((slots (compute-slots class))) + (setf (slot-value class 'slots) slots) + (setf (layout-slot-table wrapper) (make-slot-table class slots))))) ;; Comment from Gerd's PCL, 2003-05-15: ;; ;; We don't ADD-SLOT-ACCESSORS here because we don't want to @@ -510,7 +549,7 @@ ;; remove slot accessors but never put them back. I've added a ;; REINITIALIZE-INSTANCE :AFTER (CONDITION-CLASS) method, but what ;; was meant to happen? -- CSR, 2005-11-18 - (update-pv-table-cache-info class)) + ) (defmethod direct-slot-definition-class ((class condition-class) &rest initargs) @@ -616,26 +655,30 @@ (cons nil nil)))) (values defstruct-form constructor reader-names writer-names))) -(defun make-defstruct-allocation-function (class) - (let ((dd (get-structure-dd (class-name class)))) - (lambda () - (sb-kernel::%make-instance-with-layout - (sb-kernel::compiler-layout-or-lose (dd-name dd)))))) +(defun make-defstruct-allocation-function (name) + ;; FIXME: Why don't we go class->layout->info == dd + (let ((dd (find-defstruct-description name))) + (ecase (dd-type dd) + (structure + (%make-structure-instance-allocator dd nil)) + (funcallable-structure + (%make-funcallable-structure-instance-allocator dd nil))))) (defmethod shared-initialize :after ((class structure-class) slot-names &key (direct-superclasses nil direct-superclasses-p) (direct-slots nil direct-slots-p) - direct-default-initargs) + direct-default-initargs + definition-source) (declare (ignore slot-names direct-default-initargs)) (if direct-superclasses-p (setf (slot-value class 'direct-superclasses) (or direct-superclasses (setq direct-superclasses - (and (not (eq (class-name class) 'structure-object)) + (and (not (eq (slot-value class 'name) 'structure-object)) (list *the-class-structure-object*))))) (setq direct-superclasses (slot-value class 'direct-superclasses))) - (let* ((name (class-name class)) + (let* ((name (slot-value class 'name)) (from-defclass-p (slot-value class 'from-defclass-p)) (defstruct-p (or from-defclass-p (not (structure-type-p name))))) (if direct-slots-p @@ -670,18 +713,22 @@ (setf (slot-value class 'defstruct-form) defstruct-form) (setf (slot-value class 'defstruct-constructor) constructor))) (setf (slot-value class 'defstruct-constructor) - (make-defstruct-allocation-function class))) + ;; KLUDGE: not class; in fixup.lisp, can't access slots + ;; outside methods yet. + (make-defstruct-allocation-function name))) (add-direct-subclasses class direct-superclasses) (setf (slot-value class '%class-precedence-list) (compute-class-precedence-list class)) (setf (slot-value class 'cpl-available-p) t) - (setf (slot-value class 'slots) (compute-slots class)) - (let ((lclass (find-classoid (class-name class)))) - (setf (classoid-pcl-class lclass) class) - (setf (slot-value class 'wrapper) (classoid-layout lclass))) + (let ((slots (compute-slots class))) + (setf (slot-value class 'slots) slots) + (let* ((lclass (find-classoid (slot-value class 'name))) + (layout (classoid-layout lclass))) + (setf (classoid-pcl-class lclass) class) + (setf (slot-value class 'wrapper) layout) + (setf (layout-slot-table layout) (make-slot-table class slots)))) (setf (slot-value class 'finalized-p) t) - (update-pv-table-cache-info class) - (add-slot-accessors class direct-slots))) + (add-slot-accessors class direct-slots definition-source))) (defmethod direct-slot-definition-class ((class structure-class) &rest initargs) (declare (ignore initargs)) @@ -690,14 +737,14 @@ (defmethod finalize-inheritance ((class structure-class)) nil) ; always finalized -(defun add-slot-accessors (class dslotds) - (fix-slot-accessors class dslotds 'add)) +(defun add-slot-accessors (class dslotds &optional source-location) + (fix-slot-accessors class dslotds 'add source-location)) (defun remove-slot-accessors (class dslotds) (fix-slot-accessors class dslotds 'remove)) -(defun fix-slot-accessors (class dslotds add/remove) - (flet ((fix (gfspec name r/w) +(defun fix-slot-accessors (class dslotds add/remove &optional source-location) + (flet ((fix (gfspec name r/w doc) (let ((gf (cond ((eq add/remove 'add) (or (find-generic-function gfspec nil) (ensure-generic-function @@ -709,17 +756,18 @@ (when gf (case r/w (r (if (eq add/remove 'add) - (add-reader-method class gf name) + (add-reader-method class gf name doc source-location) (remove-reader-method class gf))) (w (if (eq add/remove 'add) - (add-writer-method class gf name) + (add-writer-method class gf name doc source-location) (remove-writer-method class gf)))))))) (dolist (dslotd dslotds) - (let ((slot-name (slot-definition-name dslotd))) + (let ((slot-name (slot-definition-name dslotd)) + (slot-doc (%slot-definition-documentation dslotd))) (dolist (r (slot-definition-readers dslotd)) - (fix r slot-name 'r)) + (fix r slot-name 'r slot-doc)) (dolist (w (slot-definition-writers dslotd)) - (fix w slot-name 'w)))))) + (fix w slot-name 'w slot-doc)))))) (defun add-direct-subclasses (class supers) (dolist (super supers) @@ -804,11 +852,11 @@ (when cpl (let ((first (car cpl))) (dolist (c (cdr cpl)) - (pushnew c (slot-value first 'can-precede-list)))) + (pushnew c (slot-value first 'can-precede-list) :test #'eq))) (update-class-can-precede-p (cdr cpl)))) (defun class-can-precede-p (class1 class2) - (member class2 (class-can-precede-list class1))) + (member class2 (class-can-precede-list class1) :test #'eq)) (defun update-slots (class eslotds) (let ((instance-slots ()) @@ -849,34 +897,33 @@ (make-instances-obsolete class) (class-wrapper class))))) - (with-slots (wrapper slots) class - (update-lisp-class-layout class nwrapper) - (setf slots eslotds - (wrapper-instance-slots-layout nwrapper) nlayout - (wrapper-class-slots nwrapper) nwrapper-class-slots - (wrapper-no-of-instance-slots nwrapper) nslots - wrapper nwrapper) - (do* ((slots (slot-value class 'slots) (cdr slots)) - (dupes nil)) - ((null slots) - (when dupes - (style-warn - "~@~@:>" - class dupes))) - (let* ((slot (car slots)) - (oslots (remove (slot-definition-name slot) (cdr slots) - :test #'string/= - :key #'slot-definition-name))) - (when oslots - (pushnew (cons (slot-definition-name slot) - (mapcar #'slot-definition-name oslots)) - dupes - :test #'string= :key #'car))))) + class dupes))) + (let* ((slot (car slots)) + (oslots (remove (slot-definition-name slot) (cdr slots) + :test #'string/= + :key #'slot-definition-name))) + (when oslots + (pushnew (cons (slot-definition-name slot) + (mapcar #'slot-definition-name oslots)) + dupes + :test #'string= :key #'car)))) (setf (slot-value class 'finalized-p) t) (unless (eq owrapper nwrapper) - (update-pv-table-cache-info class) (maybe-update-standard-class-locations class))))) (defun compute-class-slots (eslotds) @@ -891,9 +938,9 @@ (defun update-gfs-of-class (class) (when (and (class-finalized-p class) (let ((cpl (class-precedence-list class))) - (or (member *the-class-slot-class* cpl) + (or (member *the-class-slot-class* cpl :test #'eq) (member *the-class-standard-effective-slot-definition* - cpl)))) + cpl :test #'eq)))) (let ((gf-table (make-hash-table :test 'eq))) (labels ((collect-gfs (class) (dolist (gf (specializer-direct-generic-functions class)) @@ -1110,35 +1157,37 @@ (declare (ignore direct-slot initargs)) (find-class 'standard-reader-method)) -(defmethod add-reader-method ((class slot-class) generic-function slot-name) +(defmethod add-reader-method ((class slot-class) generic-function slot-name slot-documentation source-location) (add-method generic-function (make-a-method 'standard-reader-method () (list (or (class-name class) 'object)) (list class) (make-reader-method-function class slot-name) - "automatically generated reader method" + (or slot-documentation "automatically generated reader method") :slot-name slot-name :object-class class - :method-class-function #'reader-method-class))) + :method-class-function #'reader-method-class + :definition-source source-location))) (defmethod writer-method-class ((class slot-class) direct-slot &rest initargs) (declare (ignore direct-slot initargs)) (find-class 'standard-writer-method)) -(defmethod add-writer-method ((class slot-class) generic-function slot-name) +(defmethod add-writer-method ((class slot-class) generic-function slot-name slot-documentation source-location) (add-method generic-function (make-a-method 'standard-writer-method () (list 'new-value (or (class-name class) 'object)) (list *the-class-t* class) (make-writer-method-function class slot-name) - "automatically generated writer method" + (or slot-documentation "automatically generated writer method") :slot-name slot-name :object-class class - :method-class-function #'writer-method-class))) + :method-class-function #'writer-method-class + :definition-source source-location))) -(defmethod add-boundp-method ((class slot-class) generic-function slot-name) +(defmethod add-boundp-method ((class slot-class) generic-function slot-name slot-documentation source-location) (add-method generic-function (make-a-method (constantly (find-class 'standard-boundp-method)) class @@ -1146,8 +1195,9 @@ (list (or (class-name class) 'object)) (list class) (make-boundp-method-function class slot-name) - "automatically generated boundp method" - slot-name))) + (or slot-documentation "automatically generated boundp method") + :slot-name slot-name + :definition-source source-location))) (defmethod remove-reader-method ((class slot-class) generic-function) (let ((method (get-method generic-function () (list class) nil))) @@ -1228,12 +1278,14 @@ ;; good style. There has to be a better way! -- CSR, ;; 2002-10-29 (eq (layout-invalid owrapper) t)) - (let ((nwrapper (make-wrapper (wrapper-no-of-instance-slots owrapper) + (let ((nwrapper (make-wrapper (layout-length owrapper) class))) (setf (wrapper-instance-slots-layout nwrapper) (wrapper-instance-slots-layout owrapper)) (setf (wrapper-class-slots nwrapper) (wrapper-class-slots owrapper)) + (setf (wrapper-slot-table nwrapper) + (wrapper-slot-table owrapper)) (with-pcl-lock (update-lisp-class-layout class nwrapper) (setf (slot-value class 'wrapper) nwrapper) @@ -1255,7 +1307,7 @@ ;;; through the UPDATE-INSTANCE-FOR-REDEFINED-CLASS mechanism. (defmethod make-instances-obsolete ((class std-class)) (let* ((owrapper (class-wrapper class)) - (nwrapper (make-wrapper (wrapper-no-of-instance-slots owrapper) + (nwrapper (make-wrapper (layout-length owrapper) class))) (unless (class-finalized-p class) (if (class-has-a-forward-referenced-superclass-p class) @@ -1265,6 +1317,8 @@ (wrapper-instance-slots-layout owrapper)) (setf (wrapper-class-slots nwrapper) (wrapper-class-slots owrapper)) + (setf (wrapper-slot-table nwrapper) + (wrapper-slot-table owrapper)) (with-pcl-lock (update-lisp-class-layout class nwrapper) (setf (slot-value class 'wrapper) nwrapper) @@ -1317,7 +1371,7 @@ (type-of (obsolete-structure-datum condition)))))) (defun obsolete-instance-trap (owrapper nwrapper instance) - (if (not (pcl-instance-p instance)) + (if (not (layout-for-std-class-p owrapper)) (if *in-obsolete-instance-trap* *the-wrapper-of-structure-object* (let ((*in-obsolete-instance-trap* t)) @@ -1520,7 +1574,9 @@ ;; layout-depthoid). Is there any way we can provide a useful ;; error message? -- CSR, 2005-05-03 (eq s *the-class-file-stream*) (eq s *the-class-string-stream*) - ;; TODO + ;; This probably shouldn't be mixed in with certain other + ;; classes, too, but it seems to work both with STANDARD-OBJECT + ;; and FUNCALLABLE-STANDARD-OBJECT (eq s *the-class-sequence*))) ;;; Some necessary methods for FORWARD-REFERENCED-CLASS @@ -1539,7 +1595,7 @@ t) (defmethod add-dependent ((metaobject dependent-update-mixin) dependent) - (pushnew dependent (plist-value metaobject 'dependents))) + (pushnew dependent (plist-value metaobject 'dependents) :test #'eq)) (defmethod remove-dependent ((metaobject dependent-update-mixin) dependent) (setf (plist-value metaobject 'dependents)