(ctor-function-name ctor))))
(defun make-ctor-function-name (class-name initargs safe-code-p)
- (list* 'ctor class-name safe-code-p initargs))
+ (labels ((arg-name (x)
+ (typecase x
+ ;; this list of types might look arbitrary but it is
+ ;; exactly the set of types descended into by EQUAL,
+ ;; which is the predicate used by globaldb to test for
+ ;; name equality.
+ (list (gensym "LIST-INITARG-"))
+ (string (gensym "STRING-INITARG-"))
+ (bit-vector (gensym "BIT-VECTOR-INITARG-"))
+ (pathname (gensym "PATHNAME-INITARG-"))
+ (t x)))
+ (munge (list)
+ (let ((*gensym-counter* 0))
+ (mapcar #'arg-name list))))
+ (list* 'ctor class-name safe-code-p (munge initargs))))
;;; Keep this a separate function for testing.
(defun ensure-ctor (function-name class-name initargs safe-code-p)
'(:instance :class)))
(class-slots class))
(not maybe-invalid-initargs)
- (not (nonstandard-primary-method-p
+ (not (hairy-around-or-nonstandard-primary-method-p
ii-methods *the-system-ii-method*))
(not (around-or-nonstandard-primary-method-p
si-methods *the-system-si-method*)))
when (null qualifiers) do
(setq primary-checked-p t)))
-(defun nonstandard-primary-method-p
+(defun hairy-around-or-nonstandard-primary-method-p
(methods &optional standard-method)
(loop with primary-checked-p = nil
for method in methods
as qualifiers = (if (consp method)
(early-method-qualifiers method)
(safe-method-qualifiers method))
- when (or (and (null qualifiers)
+ when (or (and (eq :around (car qualifiers))
+ (not (simple-next-method-call-p method)))
+ (and (null qualifiers)
(not primary-checked-p)
(not (null standard-method))
(not (eq standard-method method))))
(declare (ignore ii-methods si-methods))
(let ((class (ctor-class ctor))
(lambda-list (make-ctor-parameter-list ctor))
- (initargs (quote-plist-keys (ctor-initargs ctor))))
+ (initargs (ctor-initargs ctor)))
(if use-make-instance
`(lambda ,lambda-list
(declare #.*optimize-speed*)
;; *COMPILING-OPTIMIZED-CONSTRUCTOR* which is bound around
;; compilation of the constructor, hence avoiding the
;; possibility of endless recursion.
- (make-instance ,class ,@initargs))
+ (make-instance ,class ,@(quote-plist-keys initargs)))
(let ((defaults (class-default-initargs class)))
(when defaults
(setf initargs (ctor-default-initargs initargs defaults)))
`(lambda ,lambda-list
(declare #.*optimize-speed*)
- (fast-make-instance ,class ,@initargs))))))
+ (fast-make-instance ,class ,@(quote-plist-keys initargs)))))))
;;; Not as good as the real optimizing generator, but faster than going
;;; via MAKE-INSTANCE: 1 GF call less, and no need to check initargs.
(defun optimizing-generator
(ctor ii-methods si-methods setf-svuc-slots sbuc-slots)
- (multiple-value-bind (locations names body around-or-before-method-p)
+ (multiple-value-bind (locations names body early-unbound-markers-p)
(fake-initialization-emf ctor ii-methods si-methods
setf-svuc-slots sbuc-slots)
(let ((wrapper (class-wrapper (ctor-class ctor))))
(when (layout-invalid ,wrapper)
(install-initial-constructor ,ctor)
(return (funcall ,ctor ,@(make-ctor-parameter-list ctor))))
- ,(wrap-in-allocate-forms ctor body around-or-before-method-p)))
+ ,(wrap-in-allocate-forms ctor body early-unbound-markers-p)))
locations
names
t))))
-;;; Return a form wrapped around BODY that allocates an instance
-;;; constructed by CTOR. BEFORE-METHOD-P set means we have to run
-;;; before-methods, in which case we initialize instance slots to
-;;; +SLOT-UNBOUND+. The resulting form binds the local variables
-;;; .INSTANCE. to the instance, and .SLOTS. to the instance's slot
-;;; vector around BODY.
-(defun wrap-in-allocate-forms (ctor body around-or-before-method-p)
+;;; Return a form wrapped around BODY that allocates an instance constructed
+;;; by CTOR. EARLY-UNBOUND-MARKERS-P means slots may be accessed before we
+;;; have explicitly initialized them, requiring all slots to start as
+;;; +SLOT-UNBOUND+. The resulting form binds the local variables .INSTANCE. to
+;;; the instance, and .SLOTS. to the instance's slot vector around BODY.
+(defun wrap-in-allocate-forms (ctor body early-unbound-markers-p)
(let* ((class (ctor-class ctor))
(wrapper (class-wrapper class))
(allocation-function (raw-instance-allocator class))
(get-instance-hash-code)))
(.slots. (make-array
,(layout-length wrapper)
- ,@(when around-or-before-method-p
- '(:initial-element +slot-unbound+)))))
+ ,@(when early-unbound-markers-p
+ '(:initial-element +slot-unbound+)))))
(setf (std-instance-wrapper .instance.) ,wrapper)
(setf (std-instance-slots .instance.) .slots.)
,body
(standard-sort-methods si-methods)
(declare (ignore si-primary))
(aver (null si-around))
- (let ((initargs (ctor-initargs ctor)))
+ (let ((initargs (ctor-initargs ctor))
+ ;; :BEFORE and :AROUND initialization methods, and SETF SVUC and
+ ;; SBUC methods can cause slots to be accessed before the we have
+ ;; touched them here, which requires the instance-vector to be
+ ;; initialized with +SLOT-UNBOUND+ to start with.
+ (early-unbound-markers-p (or ii-before si-before ii-around
+ setf-svuc-slots sbuc-slots)))
(multiple-value-bind
(locations names bindings vars defaulting-initargs body)
(slot-init-forms ctor
- (or ii-before si-before ii-around)
+ early-unbound-markers-p
setf-svuc-slots sbuc-slots)
(values
locations
(invoke-method ,(car ii-around) .ii-args. .next-methods.))
;; The simple case.
`(initialize-it .ii-args. nil)))))
- (or ii-before si-before ii-around)))))))
+ early-unbound-markers-p))))))
;;; Return four values from APPLICABLE-METHODS: around methods, before
;;; methods, the applicable primary method, and applicable after
(the ,type (progn ,@body)))
`(progn ,@body)))
-;;; Return as multiple values bindings for default initialization
-;;; arguments, variable names, defaulting initargs and a body for
-;;; initializing instance and class slots of an object costructed by
-;;; CTOR. The variable .SLOTS. is assumed to bound to the instance's
-;;; slot vector. BEFORE-METHOD-P T means before-methods will be
-;;; called, which means that 1) other code will initialize instance
-;;; slots to +SLOT-UNBOUND+ before the before-methods are run, and
-;;; that we have to check if these before-methods have set slots.
-(defun slot-init-forms (ctor before-method-p setf-svuc-slots sbuc-slots)
+;;; Return as multiple values bindings for default initialization arguments,
+;;; variable names, defaulting initargs and a body for initializing instance
+;;; and class slots of an object costructed by CTOR. The variable .SLOTS. is
+;;; assumed to bound to the instance's slot vector. EARLY-UNBOUND-MARKERS-P
+;;; means other code will initialize instance slots to +SLOT-UNBOUND+, and we
+;;; have to check if something has already set slots before we initialize
+;;; them.
+(defun slot-init-forms (ctor early-unbound-markers-p setf-svuc-slots sbuc-slots)
(let* ((class (ctor-class ctor))
(initargs (ctor-initargs ctor))
(initkeys (plist-keys initargs))
,value-form))))
(not-boundp-form ()
(if (member slotd sbuc-slots :test #'eq)
- `(slot-boundp-using-class
- ,class .instance. ,slotd)
+ `(not (slot-boundp-using-class
+ ,class .instance. ,slotd))
`(eq (clos-slots-ref .slots. ,i)
+slot-unbound+))))
(ecase kind
((nil)
- (unless before-method-p
+ (unless early-unbound-markers-p
`(setf (clos-slots-ref .slots. ,i)
+slot-unbound+)))
((param var)
(initfn
(setf-form `(funcall ,value)))
(initform/initfn
- (if before-method-p
+ (if early-unbound-markers-p
`(when ,(not-boundp-form)
,(setf-form `(funcall ,value)))
(setf-form `(funcall ,value))))
(initform
- (if before-method-p
+ (if early-unbound-markers-p
`(when ,(not-boundp-form)
,(setf-form `',(constant-form-value value)))
(setf-form `',(constant-form-value value))))