1.0.40.5: comment changes
[sbcl.git] / src / pcl / ctor.lisp
index 6a81d8c..5c48952 100644 (file)
          (and (symbolp constant)
               (not (null (symbol-package constant)))))))
 
-;;; somewhat akin to DEFAULT-INITARGS (SLOT-CLASS T T), but just
-;;; collecting the defaulted initargs for the call.
+;;; Somewhat akin to DEFAULT-INITARGS, but just collecting the defaulted
+;;; initargs for the call.
 (defun ctor-default-initkeys (supplied-initargs class-default-initargs)
   (loop for (key) in class-default-initargs
         when (eq (getf supplied-initargs key '.not-there.) '.not-there.)
         collect key))
+
+;;; Like DEFAULT-INITARGS, but return a list that can be spliced into source,
+;;; instead of a list with values already evaluated.
+(defun ctor-default-initargs (supplied-initargs class-default-initargs)
+  (loop for (key form fun) in class-default-initargs
+        when (eq (getf supplied-initargs key '.not-there.) '.not-there.)
+        append (list key (if (constantp form) form `(funcall ,fun)))
+          into default-initargs
+        finally
+          (return (append supplied-initargs default-initargs))))
 \f
 ;;; *****************
 ;;; CTORS   *********
 
 ;;; 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)))
 \f
 ;;; *****************
 ;;; Inline CTOR cache
       (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))))))
 \f
 ;;; ***********************************************
 ;;; Compile-Time Expansion of MAKE-INSTANCE *******
 
 (define-compiler-macro make-instance (&whole form &rest args &environment env)
   (declare (ignore args))
-  ;; Compiling an optimized constructor for a non-standard class means compiling a
-  ;; lambda with (MAKE-INSTANCE #<SOME-CLASS X> ...) in it -- need
-  ;; to make sure we don't recurse there.
+  ;; Compiling an optimized constructor for a non-standard class means
+  ;; compiling a lambda with (MAKE-INSTANCE #<SOME-CLASS X> ...) in it
+  ;; -- need to make sure we don't recurse there.
   (or (unless *compiling-optimized-constructor*
         (make-instance->constructor-call form (safe-code-p env)))
       form))
                 (setf (info :function :where-from function-name) :defined)
                 (when (info :function :assumed-type function-name)
                   (setf (info :function :assumed-type function-name) nil)))
-              ;; Return code constructing a ctor at load time, which, when
-              ;; called, will set its funcallable instance function to an
-              ;; optimized constructor function.
+              ;; Return code constructing a ctor at load time, which,
+              ;; when called, will set its funcallable instance
+              ;; function to an optimized constructor function.
               `(locally
                    (declare (disable-package-locks ,function-name))
                  (let ((.x. (load-time-value
                                (function (&rest t) t))
                            ,function-name))
                    (funcall (function ,function-name) ,@value-forms))))
-            (when class-arg
-              ;; Build an inline cache: a CONS, with the actual cache in the CDR.
+            (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))
                  (let* ((.cache. (load-time-value (cons 'ctor-cache nil)))
                         (.class-arg. ,class-arg))
                    (multiple-value-bind (.fun. .new-store.)
                        (ensure-cached-ctor .class-arg. .store. ',initargs ',safe-code-p)
-                     ;; Thread safe: if multiple threads hit this in paralle, the update
-                     ;; from the other one is just lost -- no harm done, except for the
-                     ;; need to redo the work next time.
+                     ;; Thread safe: if multiple threads hit this in
+                     ;; parallel, the update from the other one is
+                     ;; just lost -- no harm done, except for the need
+                     ;; to redo the work next time.
                      (unless (eq .store. .new-store.)
                        (setf (cdr .cache.) .new-store.))
                      (funcall (truly-the function .fun.) ,@value-forms))))))))))
                 (constructor-function-form ctor)
               (apply
                (let ((*compiling-optimized-constructor* t))
-                 (compile nil `(lambda ,names ,form)))
+                 (handler-bind ((compiler-note #'muffle-warning))
+                   (compile nil `(lambda ,names ,form))))
                locations))))))
 
 (defun constructor-function-form (ctor)
         `(lambda ,lambda-list
            (declare #.*optimize-speed*)
            ;; The CTOR MAKE-INSTANCE optimization checks for
-           ;; *COMPILING-OPTIMIZED-CONSTRUCTOR* which is bound around compilation of
-           ;; the constructor, hence avoiding the possibility of endless recursion.
+           ;; *COMPILING-OPTIMIZED-CONSTRUCTOR* which is bound around
+           ;; compilation of the constructor, hence avoiding the
+           ;; possibility of endless recursion.
            (make-instance ,class ,@initargs))
         (let ((defaults (class-default-initargs class)))
           (when defaults
-            (setf initargs (default-initargs initargs defaults)))
+            (setf initargs (ctor-default-initargs initargs defaults)))
           `(lambda ,lambda-list
              (declare #.*optimize-speed*)
              (fast-make-instance ,class ,@initargs))))))
 ;;; *******************************
 
 (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
        (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))
         (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)
                             (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))))