X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fpcl%2Fctor.lisp;h=6f703adbf3568d15292be1ff09841de2a08b0720;hb=ab7aedfb1e4c0245814beb998e74e099b71092a6;hp=04daadf1776160a505df0655ab1808dd4c3e4a55;hpb=aa8cdb795d6bb551aaecb6db38d5ef6571c698ed;p=sbcl.git diff --git a/src/pcl/ctor.lisp b/src/pcl/ctor.lisp index 04daadf..6f703ad 100644 --- a/src/pcl/ctor.lisp +++ b/src/pcl/ctor.lisp @@ -155,17 +155,19 @@ ;;; Keep this a separate function for testing. (defun ensure-ctor (function-name class-name initargs safe-code-p) - (unless (fboundp function-name) - (make-ctor function-name class-name initargs safe-code-p))) + (with-world-lock () + (if (fboundp function-name) + (the ctor (fdefinition function-name)) + (make-ctor function-name class-name initargs safe-code-p)))) ;;; Keep this a separate function for testing. (defun make-ctor (function-name class-name initargs safe-p) (without-package-locks ; for (setf symbol-function) - (let ((ctor (%make-ctor function-name class-name nil initargs safe-p))) - (push ctor *all-ctors*) - (setf (fdefinition function-name) ctor) - (install-initial-constructor ctor :force-p t) - ctor))) + (let ((ctor (%make-ctor function-name class-name nil initargs safe-p))) + (install-initial-constructor ctor :force-p t) + (push ctor *all-ctors*) + (setf (fdefinition function-name) ctor) + ctor))) ;;; ***************** ;;; Inline CTOR cache @@ -308,25 +310,35 @@ (setf table (nth-value 1 (put-ctor ctor table)))) table)) -(defun ctor-for-caching (class-name initargs safe-code-p) - (let ((name (make-ctor-function-name class-name initargs safe-code-p))) - (or (ensure-ctor name class-name initargs safe-code-p) - (fdefinition name)))) - (defun ensure-cached-ctor (class-name store initargs safe-code-p) - (if (listp store) - (multiple-value-bind (ctor list) (find-ctor class-name store) - (if ctor - (values ctor list) - (let ((ctor (ctor-for-caching class-name initargs safe-code-p))) - (if (< (length list) +ctor-list-max-size+) - (values ctor (cons ctor list)) - (values ctor (ctor-list-to-table list)))))) - (let ((ctor (get-ctor class-name store))) - (if ctor - (values ctor store) - (put-ctor (ctor-for-caching class-name initargs safe-code-p) - store))))) + (flet ((maybe-ctor-for-caching () + (if (typep class-name '(or symbol class)) + (let ((name (make-ctor-function-name class-name initargs safe-code-p))) + (ensure-ctor name class-name initargs safe-code-p)) + ;; Invalid first argument: let MAKE-INSTANCE worry about it. + (return-from ensure-cached-ctor + (values (lambda (&rest ctor-parameters) + (let (mi-initargs) + (doplist (key value) initargs + (push key mi-initargs) + (push (if (constantp value) + value + (pop ctor-parameters)) + mi-initargs)) + (apply #'make-instance class-name (nreverse mi-initargs)))) + store))))) + (if (listp store) + (multiple-value-bind (ctor list) (find-ctor class-name store) + (if ctor + (values ctor list) + (let ((ctor (maybe-ctor-for-caching))) + (if (< (length list) +ctor-list-max-size+) + (values ctor (cons ctor list)) + (values ctor (ctor-list-to-table list)))))) + (let ((ctor (get-ctor class-name store))) + (if ctor + (values ctor store) + (put-ctor (maybe-ctor-for-caching) store)))))) ;;; *********************************************** ;;; Compile-Time Expansion of MAKE-INSTANCE ******* @@ -407,7 +419,7 @@ (function (&rest t) t)) ,function-name)) (funcall (function ,function-name) ,@value-forms)))) - (when class-arg + (when (and class-arg (not (constantp class-arg))) ;; Build an inline cache: a CONS, with the actual cache in the CDR. `(locally (declare (disable-package-locks .cache. .class-arg. .store. .fun. make-instance)) @@ -896,14 +908,15 @@ ;;; ******************************* (defun update-ctors (reason &key class name generic-function method) - (labels ((reset (class &optional ri-cache-p (ctorsp t)) + (labels ((reset (class &optional initarg-caches-p (ctorsp t)) (when ctorsp (dolist (ctor (plist-value class 'ctors)) (install-initial-constructor ctor))) - (when ri-cache-p - (setf (plist-value class 'ri-initargs) ())) + (when initarg-caches-p + (dolist (cache '(mi-initargs ri-initargs)) + (setf (plist-value class cache) ()))) (dolist (subclass (class-direct-subclasses class)) - (reset subclass ri-cache-p ctorsp)))) + (reset subclass initarg-caches-p ctorsp)))) (ecase reason ;; CLASS must have been specified. (finalize-inheritance @@ -920,8 +933,16 @@ (flet ((class-of-1st-method-param (method) (type-class (first (method-specializers method))))) (case (generic-function-name generic-function) - ((make-instance allocate-instance - initialize-instance shared-initialize) + ((make-instance allocate-instance) + ;; FIXME: I can't see a way of working out which classes a + ;; given metaclass specializer are applicable to short of + ;; iterating and testing with class-of. It would be good + ;; to not invalidate caches of system classes at this + ;; point (where it is not legal to define a method + ;; applicable to them on system functions). -- CSR, + ;; 2010-07-13 + (reset (find-class 'standard-object) t t)) + ((initialize-instance shared-initialize) (reset (class-of-1st-method-param method) t t)) ((reinitialize-instance) (reset (class-of-1st-method-param method) t nil)) @@ -941,11 +962,35 @@ (when (and class (class-finalized-p class)) (install-optimized-constructor ctor)))))) +;;; FIXME: CHECK-FOO-INITARGS share most of their bodies. +(defun check-mi-initargs (class initargs) + (let* ((class-proto (class-prototype class)) + (keys (plist-keys initargs)) + (cache (plist-value class 'mi-initargs)) + (cached (assoc keys cache :test #'equal)) + (invalid-keys + (if (consp cached) + (cdr cached) + (let ((invalid + (check-initargs-1 + class initargs + (list (list* 'allocate-instance class initargs) + (list* 'initialize-instance class-proto initargs) + (list* 'shared-initialize class-proto t initargs)) + t nil))) + (setf (plist-value class 'mi-initargs) + (acons keys invalid cache)) + invalid)))) + (when invalid-keys + ;; FIXME: should have an operation here, and maybe a set of + ;; valid keys. + (error 'initarg-error :class class :initargs invalid-keys)))) + (defun check-ri-initargs (instance initargs) (let* ((class (class-of instance)) (keys (plist-keys initargs)) - (cached (assoc keys (plist-value class 'ri-initargs) - :test #'equal)) + (cache (plist-value class 'ri-initargs)) + (cached (assoc keys cache :test #'equal)) (invalid-keys (if (consp cached) (cdr cached) @@ -959,7 +1004,7 @@ (list* 'shared-initialize instance nil initargs)) t nil))) (setf (plist-value class 'ri-initargs) - (acons keys invalid cached)) + (acons keys invalid cache)) invalid)))) (when invalid-keys (error 'initarg-error :class class :initargs invalid-keys))))