(defmacro early-gf-methods (gf)
`(clos-slots-ref (get-slots ,gf) *sgf-methods-index*))
+(defun safe-generic-function-methods (generic-function)
+ (if (eq (class-of generic-function) *the-class-standard-generic-function*)
+ (clos-slots-ref (get-slots generic-function) *sgf-methods-index*)
+ (generic-function-methods generic-function)))
+
(defvar *sgf-arg-info-index*
(!bootstrap-slot-index 'standard-generic-function 'arg-info))
~S."
gf-keywords)))))))
+(defvar *sm-specializers-index*
+ (!bootstrap-slot-index 'standard-method 'specializers))
+(defvar *sm-fast-function-index*
+ (!bootstrap-slot-index 'standard-method 'fast-function))
+(defvar *sm-function-index*
+ (!bootstrap-slot-index 'standard-method 'function))
+(defvar *sm-plist-index*
+ (!bootstrap-slot-index 'standard-method 'plist))
+
+;;; FIXME: we don't actually need this; we could test for the exact
+;;; class and deal with it as appropriate. In fact we probably don't
+;;; need it anyway because we only use this for METHOD-SPECIALIZERS on
+;;; the standard reader method for METHOD-SPECIALIZERS. Probably.
+(dolist (s '(specializers fast-function function plist))
+ (aver (= (symbol-value (intern (format nil "*SM-~A-INDEX*" s)))
+ (!bootstrap-slot-index 'standard-reader-method s)
+ (!bootstrap-slot-index 'standard-writer-method s)
+ (!bootstrap-slot-index 'standard-boundp-method s))))
+
+(defun safe-method-specializers (method)
+ (let ((standard-method-classes
+ (list *the-class-standard-method*
+ *the-class-standard-reader-method*
+ *the-class-standard-writer-method*
+ *the-class-standard-boundp-method*))
+ (class (class-of method)))
+ (if (member class standard-method-classes)
+ (clos-slots-ref (get-slots method) *sm-specializers-index*)
+ (method-specializers method))))
+(defun safe-method-fast-function (method)
+ (let ((standard-method-classes
+ (list *the-class-standard-method*
+ *the-class-standard-reader-method*
+ *the-class-standard-writer-method*
+ *the-class-standard-boundp-method*))
+ (class (class-of method)))
+ (if (member class standard-method-classes)
+ (clos-slots-ref (get-slots method) *sm-fast-function-index*)
+ (method-fast-function method))))
+(defun safe-method-function (method)
+ (let ((standard-method-classes
+ (list *the-class-standard-method*
+ *the-class-standard-reader-method*
+ *the-class-standard-writer-method*
+ *the-class-standard-boundp-method*))
+ (class (class-of method)))
+ (if (member class standard-method-classes)
+ (clos-slots-ref (get-slots method) *sm-function-index*)
+ (method-function method))))
+(defun safe-method-qualifiers (method)
+ (let ((standard-method-classes
+ (list *the-class-standard-method*
+ *the-class-standard-reader-method*
+ *the-class-standard-writer-method*
+ *the-class-standard-boundp-method*))
+ (class (class-of method)))
+ (if (member class standard-method-classes)
+ (let ((plist (clos-slots-ref (get-slots method) *sm-plist-index*)))
+ (getf plist 'qualifiers))
+ (method-qualifiers method))))
+
(defun set-arg-info1 (gf arg-info new-method methods was-valid-p first-p)
(let* ((existing-p (and methods (cdr methods) new-method))
(nreq (length (arg-info-metatypes arg-info)))
(dolist (method (if new-method (list new-method) methods))
(let* ((specializers (if (or (eq *boot-state* 'complete)
(not (consp method)))
- (method-specializers method)
+ (safe-method-specializers method)
(early-method-specializers method t)))
(class (if (or (eq *boot-state* 'complete) (not (consp method)))
(class-of method)
(set-arg-info fin :lambda-list lambda-list))))
fin))
+(defun safe-gf-dfun-state (generic-function)
+ (if (eq (class-of generic-function) *the-class-standard-generic-function*)
+ (clos-slots-ref (get-slots generic-function) *sgf-dfun-state-index*)
+ (gf-dfun-state generic-function)))
+(defun (setf safe-gf-dfun-state) (new-value generic-function)
+ (if (eq (class-of generic-function) *the-class-standard-generic-function*)
+ (setf (clos-slots-ref (get-slots generic-function)
+ *sgf-dfun-state-index*)
+ new-value)
+ (setf (gf-dfun-state generic-function) new-value)))
+
(defun set-dfun (gf &optional dfun cache info)
(when cache
(setf (cache-owner cache) gf))
(list* dfun cache info)
dfun)))
(if (eq *boot-state* 'complete)
- (if (eq (class-of gf) *the-class-standard-generic-function*)
- ;; break metacircles: see sbcl-devel 2006-01-15 and #lisp
- ;; IRC logs 2006-01-16 for the hilarity.
- (setf (clos-slots-ref (get-slots gf) *sgf-dfun-state-index*)
- new-state)
- (setf (gf-dfun-state gf) new-state))
+ (setf (safe-gf-dfun-state gf) new-state)
(setf (clos-slots-ref (get-slots gf) *sgf-dfun-state-index*)
new-state)))
dfun)
(defun gf-dfun-cache (gf)
(let ((state (if (eq *boot-state* 'complete)
- (if (eq (class-of gf) *the-class-standard-generic-function*)
- (clos-slots-ref (get-slots gf) *sgf-dfun-state-index*)
- (gf-dfun-state gf))
+ (safe-gf-dfun-state gf)
(clos-slots-ref (get-slots gf) *sgf-dfun-state-index*))))
(typecase state
(function nil)
(defun gf-dfun-info (gf)
(let ((state (if (eq *boot-state* 'complete)
- (if (eq (class-of gf) *the-class-standard-generic-function*)
- (clos-slots-ref (get-slots gf) *sgf-dfun-state-index*)
- (gf-dfun-state gf))
+ (safe-gf-dfun-state gf)
(clos-slots-ref (get-slots gf) *sgf-dfun-state-index*))))
(typecase state
(function nil)
(when lambda-list-p
(proclaim (defgeneric-declaration fun-name lambda-list)))))
\f
+(defun safe-gf-arg-info (generic-function)
+ (if (eq (class-of generic-function) *the-class-standard-generic-function*)
+ (clos-slots-ref (fsc-instance-slots generic-function)
+ *sgf-arg-info-index*)
+ (gf-arg-info generic-function)))
+
;;; FIXME: this function took on a slightly greater role than it
;;; previously had around 2005-11-02, when CSR fixed the bug whereby
;;; having more than one subclass of standard-generic-function caused
(multiple-value-bind (applyp metatypes arg-info)
(let* ((arg-info (if (early-gf-p gf)
(early-gf-arg-info gf)
- (if (eq (class-of gf) *the-class-standard-generic-function*)
- (clos-slots-ref (fsc-instance-slots gf) *sgf-arg-info-index*)
- (gf-arg-info gf))))
+ (safe-gf-arg-info gf)))
(metatypes (arg-info-metatypes arg-info)))
(values (arg-info-applyp arg-info)
metatypes
(some (lambda (method)
(let ((fmf (if (listp method)
(third method)
- (method-fast-function method))))
+ (safe-method-fast-function method))))
(method-function-get fmf :slot-name-lists)))
;; KLUDGE: As of sbcl-0.6.4, it's very important for
;; efficiency to know the type of the sequence argument to
(dolist (method methods t)
(when (eq *boot-state* 'complete)
(when (or (some #'eql-specializer-p
- (method-specializers method))
- (method-qualifiers method))
+ (safe-method-specializers method))
+ (safe-method-qualifiers method))
(return nil)))
(let ((value (method-function-get
(if early-p
(or (third method) (second method))
- (or (method-fast-function method)
- (method-function method)))
+ (or (safe-method-fast-function method)
+ (safe-method-function method)))
:constant-value default)))
(when (or (eq value default)
(and boolean-values-p
(let ((definite-p t) (possibly-applicable-methods nil))
(dolist (method (if (early-gf-p generic-function)
(early-gf-methods generic-function)
- (if (eq (class-of generic-function)
- *the-class-standard-generic-function*)
- ;; KLUDGE: see comment by GET-GENERIC-FUN-INFO
- (clos-slots-ref (fsc-instance-slots generic-function) *sgf-methods-index*)
- (generic-function-methods generic-function))))
+ (safe-generic-function-methods generic-function)))
(let ((specls (if (consp method)
(early-method-specializers method t)
- (method-specializers method)))
+ (safe-method-specializers method)))
(types types)
(possibly-applicable-p t) (applicable-p t))
(dolist (specl specls)
--- /dev/null
+;;;; miscellaneous side-effectful tests of the MOP
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; While most of SBCL is derived from the CMU CL system, the test
+;;;; files (like this one) were written from scratch after the fork
+;;;; from CMU CL.
+;;;;
+;;;; This software is in the public domain and is provided with
+;;;; absolutely no warranty. See the COPYING and CREDITS files for
+;;;; more information.
+
+;;; this file attempts to test possible metacircularity issues arising
+;;; from adding slots to methods in odd places.
+
+(defpackage "MOP-12"
+ (:use "CL" "SB-MOP"))
+
+(in-package "MOP-12")
+
+(defclass super-method ()
+ ((abc :accessor abc :initarg :abc)))
+
+;;; Test case reported by Jean Bresson sbcl-devel 2006-02-09
+(defclass sub-generic-function1 (standard-generic-function) ()
+ (:metaclass funcallable-standard-class))
+
+(defclass sub-method1 (standard-method super-method) ())
+
+(defgeneric myfun1 (a b)
+ (:generic-function-class sub-generic-function1)
+ (:method-class sub-method1))
+
+(defvar *count1* 0)
+
+(defmethod myfun1 (a b)
+ (incf *count1*))
+
+(myfun1 2 3)
+(assert (= *count1* 1))
+(myfun1 t nil)
+(assert (= *count1* 2))
+
+(defmethod myfun1 ((a integer) (b integer))
+ (incf *count1* 2))
+
+(myfun1 2 3)
+(assert (= *count1* 4))
+(myfun1 t nil)
+(assert (= *count1* 5))
+
+;;; Friendlier superclass order test case from Pascal Costanza
+;;; sbcl-devel 2006-02-09
+(defclass sub-generic-function2 (standard-generic-function) ()
+ (:metaclass funcallable-standard-class))
+
+(defclass sub-method2 (super-method standard-method) ())
+
+(defgeneric myfun2 (a b)
+ (:generic-function-class sub-generic-function2)
+ (:method-class sub-method2))
+
+(defvar *count2* 0)
+
+(defmethod myfun2 (a b)
+ (incf *count2*))
+
+(myfun2 2 3)
+(assert (= *count2* 1))
+(myfun2 t nil)
+(assert (= *count2* 2))
+
+(defmethod myfun2 ((a integer) (b integer))
+ (incf *count2* 2))
+
+(myfun2 2 3)
+(assert (= *count2* 4))
+(myfun2 t nil)
+(assert (= *count2* 5))
--- /dev/null
+;;;; miscellaneous side-effectful tests of the MOP
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; While most of SBCL is derived from the CMU CL system, the test
+;;;; files (like this one) were written from scratch after the fork
+;;;; from CMU CL.
+;;;;
+;;;; This software is in the public domain and is provided with
+;;;; absolutely no warranty. See the COPYING and CREDITS files for
+;;;; more information.
+
+;;; this file attempts to test possible metacircularity issues arising
+;;; from adding slots to generic functions in odd places.
+
+(defpackage "MOP-13"
+ (:use "CL" "SB-MOP"))
+
+(in-package "MOP-13")
+
+(defclass super-funcallable-mixin ()
+ ((abc :accessor abc :initarg :abc))
+ (:metaclass funcallable-standard-class))
+
+(defclass sub-generic-function1 (standard-generic-function
+ super-funcallable-mixin) ()
+ (:metaclass funcallable-standard-class))
+
+(defclass sub-method1 (standard-method) ())
+
+(defgeneric myfun1 (a b)
+ (:generic-function-class sub-generic-function1)
+ (:method-class sub-method1))
+
+(defvar *count1* 0)
+
+(defmethod myfun1 (a b)
+ (incf *count1*))
+
+(myfun1 2 3)
+(assert (= *count1* 1))
+(myfun1 t nil)
+(assert (= *count1* 2))
+
+(defmethod myfun1 ((a integer) (b integer))
+ (incf *count1* 2))
+
+(myfun1 2 3)
+(assert (= *count1* 4))
+(myfun1 t nil)
+(assert (= *count1* 5))
+
+;;; Friendlier superclass order test case
+(defclass sub-generic-function2 (super-funcallable-mixin
+ standard-generic-function) ()
+ (:metaclass funcallable-standard-class))
+
+(defclass sub-method2 (standard-method) ())
+
+(defgeneric myfun2 (a b)
+ (:generic-function-class sub-generic-function2)
+ (:method-class sub-method2))
+
+(defvar *count2* 0)
+
+(defmethod myfun2 (a b)
+ (incf *count2*))
+
+(myfun2 2 3)
+(assert (= *count2* 1))
+(myfun2 t nil)
+(assert (= *count2* 2))
+
+(defmethod myfun2 ((a integer) (b integer))
+ (incf *count2* 2))
+
+(myfun2 2 3)
+(assert (= *count2* 4))
+(myfun2 t nil)
+(assert (= *count2* 5))