1.0.33.22: fix WITH-MUTEX docstring
[sbcl.git] / src / pcl / ctor.lisp
index 26b64e2..6584142 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   *********
 ;;; optimized constructor function when called.
 (defun install-initial-constructor (ctor &key force-p)
   (when (or force-p (ctor-class ctor))
-    (let ((*installing-ctor* t))
-      (setf (ctor-class ctor) nil)
-      (setf (funcallable-instance-fun ctor)
-            #'(lambda (&rest args)
-                (install-optimized-constructor ctor)
-                (apply ctor args)))
-      (setf (%funcallable-instance-info ctor 1)
-            (ctor-function-name ctor)))))
+    (setf (ctor-class ctor) nil)
+    (setf (funcallable-instance-fun ctor)
+          #'(lambda (&rest args)
+              (install-optimized-constructor ctor)
+              (apply ctor args)))
+    (setf (%funcallable-instance-info ctor 1)
+          (ctor-function-name ctor))))
 
 (defun make-ctor-function-name (class-name initargs safe-code-p)
   (list* 'ctor class-name safe-code-p initargs))
 
 ;;; 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 *******
                                (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))
                 (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)
     ;; MAKE-INSTANCE and/or ALLOCATE-INSTANCE, these will show up
     ;; together with the system-defined ones in what
     ;; COMPUTE-APPLICABLE-METHODS returns.
-    (if (and (not (structure-class-p class))
-             (not (condition-class-p class))
-             (null (cdr make-instance-methods))
-             (null (cdr allocate-instance-methods))
-             (every (lambda (x)
-                      (member (slot-definition-allocation x)
-                              '(:instance :class)))
-                    (class-slots class))
-             (null (check-initargs-1
-                    class
-                    (append
-                     (ctor-default-initkeys
-                      (ctor-initargs ctor) (class-default-initargs class))
-                     (plist-keys (ctor-initargs ctor)))
-                    (append ii-methods si-methods) nil nil))
-             (not (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*))
-             ;; the instance structure protocol goes through
-             ;; slot-value(-using-class) and friends (actually just
-             ;; (SETF SLOT-VALUE-USING-CLASS) and
-             ;; SLOT-BOUNDP-USING-CLASS), so if there are non-standard
-             ;; applicable methods we can't shortcircuit them.
-             (every (lambda (x) (= (length x) 1)) setf-svuc-slots-methods)
-             (every (lambda (x) (= (length x) 1)) sbuc-slots-methods))
-        (optimizing-generator ctor ii-methods si-methods)
-        (fallback-generator ctor ii-methods si-methods))))
+    (let ((maybe-invalid-initargs
+           (check-initargs-1
+            class
+            (append
+             (ctor-default-initkeys
+              (ctor-initargs ctor) (class-default-initargs class))
+             (plist-keys (ctor-initargs ctor)))
+            (append ii-methods si-methods) nil nil))
+          (custom-make-instance
+           (not (null (cdr make-instance-methods)))))
+      (if (and (not (structure-class-p class))
+               (not (condition-class-p class))
+               (not custom-make-instance)
+               (null (cdr allocate-instance-methods))
+               (every (lambda (x)
+                        (member (slot-definition-allocation x)
+                                '(:instance :class)))
+                      (class-slots class))
+               (not maybe-invalid-initargs)
+               (not (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*))
+               ;; the instance structure protocol goes through
+               ;; slot-value(-using-class) and friends (actually just
+               ;; (SETF SLOT-VALUE-USING-CLASS) and
+               ;; SLOT-BOUNDP-USING-CLASS), so if there are non-standard
+               ;; applicable methods we can't shortcircuit them.
+               (every (lambda (x) (= (length x) 1)) setf-svuc-slots-methods)
+               (every (lambda (x) (= (length x) 1)) sbuc-slots-methods))
+          (optimizing-generator ctor ii-methods si-methods)
+          (fallback-generator ctor ii-methods si-methods
+                              (or maybe-invalid-initargs custom-make-instance))))))
 
 (defun around-or-nonstandard-primary-method-p
     (methods &optional standard-method)
         when (null qualifiers) do
           (setq primary-checked-p t)))
 
-(defun fallback-generator (ctor ii-methods si-methods)
+(defun fallback-generator (ctor ii-methods si-methods use-make-instance)
   (declare (ignore ii-methods si-methods))
-  `(lambda ,(make-ctor-parameter-list ctor)
-     ;; The CTOR MAKE-INSTANCE optimization only kicks in when the
-     ;; first argument to MAKE-INSTANCE is a constant symbol: by
-     ;; calling it with a class, as here, we inhibit the optimization,
-     ;; so removing the possibility of endless recursion.  -- CSR,
-     ;; 2004-07-12
-     (make-instance ,(ctor-class ctor)
-      ,@(quote-plist-keys (ctor-initargs ctor)))))
+  (let ((class (ctor-class ctor))
+        (lambda-list (make-ctor-parameter-list ctor))
+        (initargs (quote-plist-keys (ctor-initargs ctor))))
+    (if use-make-instance
+        `(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.
+           (make-instance ,class ,@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))))))
+
+;;; 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 fast-make-instance (class &rest initargs)
+  (declare #.*optimize-speed*)
+  (declare (dynamic-extent initargs))
+  (let ((.instance. (apply #'allocate-instance class initargs)))
+    (apply #'initialize-instance .instance. initargs)
+    .instance.))
 
 (defun optimizing-generator (ctor ii-methods si-methods)
   (multiple-value-bind (locations names body before-method-p)