1.0.8.41: doc spelling fixes.
[sbcl.git] / src / pcl / vector.lisp
index 549c5e3..4b7fcfe 100644 (file)
@@ -33,9 +33,6 @@
          (when (eq ,slot-name sn) (return-from loop pos))
          (incf pos)))))
 \f
-(defun pv-cache-limit-fn (nlines)
-  (default-limit-fn nlines))
-
 (defstruct (pv-table (:predicate pv-tablep)
                      (:constructor make-pv-table-internal
                                    (slot-name-lists call-list))
          (call-list (pv-table-call-list pv-table))
          (cache (or (pv-table-cache pv-table)
                     (setf (pv-table-cache pv-table)
-                          (get-cache (- (length slot-name-lists)
-                                        (count nil slot-name-lists))
-                                     t
-                                     #'pv-cache-limit-fn
-                                     2)))))
-    (or (probe-cache cache pv-wrappers)
-        (let* ((pv (compute-pv slot-name-lists pv-wrappers))
-               (calls (compute-calls call-list pv-wrappers))
-               (pv-cell (cons pv calls))
-               (new-cache (fill-cache cache pv-wrappers pv-cell)))
-          (unless (eq new-cache cache)
-            (setf (pv-table-cache pv-table) new-cache))
-          pv-cell))))
+                          (make-cache :key-count (- (length slot-name-lists)
+                                                    (count nil slot-name-lists))
+                                      :value t
+                                      :size 2)))))
+    (multiple-value-bind (hitp value) (probe-cache cache pv-wrappers)
+      (if hitp
+          value
+          (let* ((pv (compute-pv slot-name-lists pv-wrappers))
+                 (calls (compute-calls call-list pv-wrappers))
+                 (pv-cell (cons pv calls))
+                 (new-cache (fill-cache cache pv-wrappers pv-cell)))
+            ;; This is safe: if another thread races us here the loser just
+            ;; misses the next time as well.
+            (unless (eq new-cache cache)
+              (setf (pv-table-cache pv-table) new-cache))
+            pv-cell)))))
 
 (defun make-pv-type-declaration (var)
   `(type simple-vector ,var))
 
-(defmacro pvref (pv index)
-  `(svref ,pv ,index))
-
 (defmacro copy-pv (pv)
   `(copy-seq ,pv))
 
           (let ((map (svref pv-map i)))
             (when map
               (aver (= (car map) 0))
-              (setf (pvref pv i) (cdr map))))))
+              (setf (svref pv i) (cdr map))))))
       (when (memq cwrapper wrappers)
         (let ((param 0))
           (dolist (wrapper wrappers)
               (dotimes-fixnum (i pv-size)
                 (let ((map (svref pv-map i)))
                   (when (and map (= (car map) param))
-                    (setf (pvref pv i) (cdr map))))))
+                    (setf (svref pv i) (cdr map))))))
             (incf param))))))
 \f
 (defun can-optimize-access (form required-parameters env)
-  (let ((type (ecase (car form)
-                (slot-value 'reader)
-                (set-slot-value 'writer)
-                (slot-boundp 'boundp)))
-        (var (cadr form))
-        (slot-name (eval (caddr form)))) ; known to be constant
-    (can-optimize-access1 var required-parameters env type slot-name)))
-
-;;; FIXME: This looks like an internal helper function for
-;;; CAN-OPTIMIZE-ACCESS, and it is used that way, but it's also called
-;;; bare from several places in the code. Perhaps the two functions
-;;; should be renamed CAN-OPTIMIZE-ACCESS-FOR-FORM and
-;;; CAN-OPTIMIZE-ACCESS-FOR-VAR. If so, I'd just as soon use keyword
-;;; args instead of optional ones, too.
-(defun can-optimize-access1 (var required-parameters env
-                             &optional type slot-name)
-  (when (and (consp var) (eq 'the (car var)))
-    ;; FIXME: We should assert list of length 3 here. Or maybe we
-    ;; should just define EXTRACT-THE, replace the whole
-    ;;   (WHEN ..)
-    ;; form with
-    ;;   (AWHEN (EXTRACT-THE VAR)
-    ;;     (SETF VAR IT))
-    ;; and then use EXTRACT-THE similarly to clean up the other tests
-    ;; against 'THE scattered through the PCL code.
-    (setq var (caddr var)))
-  (when (symbolp var)
-    (let* ((rebound? (caddr (var-declaration '%variable-rebinding var env)))
-           (parameter-or-nil (car (memq (or rebound? var)
-                                        required-parameters))))
-      (when parameter-or-nil
-        (let* ((class-name (caddr (var-declaration '%class
-                                                   parameter-or-nil
-                                                   env)))
-               (class (find-class class-name nil)))
-          (when (or (not (eq *boot-state* 'complete))
-                    (and class (not (class-finalized-p class))))
-            (setq class nil))
-          (when (and class-name (not (eq class-name t)))
-            (when (or (null type)
-                      (not (and class
-                                (memq *the-class-structure-object*
-                                      (class-precedence-list class))))
-                      (optimize-slot-value-by-class-p class slot-name type))
-              (cons parameter-or-nil (or class class-name)))))))))
+  (destructuring-bind (op var-form slot-name-form &optional new-value) form
+      (let ((type (ecase op
+                    (slot-value 'reader)
+                    (set-slot-value 'writer)
+                    (slot-boundp 'boundp)))
+            (var (extract-the var-form))
+            (slot-name (constant-form-value slot-name-form env)))
+        (when (symbolp var)
+          (let* ((rebound? (caddr (var-declaration '%variable-rebinding var env)))
+                 (parameter-or-nil (car (memq (or rebound? var)
+                                              required-parameters))))
+            (when parameter-or-nil
+              (let* ((class-name (caddr (var-declaration '%class
+                                                         parameter-or-nil
+                                                         env)))
+                     (class (find-class class-name nil)))
+                (when (or (not (eq *boot-state* 'complete))
+                          (and class (not (class-finalized-p class))))
+                  (setq class nil))
+                (when (and class-name (not (eq class-name t)))
+                  (when (or (null type)
+                            (not (and class
+                                      (memq *the-class-structure-object*
+                                            (class-precedence-list class))))
+                            (optimize-slot-value-by-class-p class slot-name type))
+                    (values (cons parameter-or-nil (or class class-name))
+                            slot-name
+                            new-value))))))))))
 
 ;;; Check whether the binding of the named variable is modified in the
 ;;; method body.
   (let ((modified-variables (macroexpand '%parameter-binding-modified env)))
     (memq parameter-name modified-variables)))
 
-(defun optimize-slot-value (slots sparameter form)
-  (if sparameter
-      (let ((optimized-form
-             (destructuring-bind (ignore1 ignore2 slot-name-form) form
-               (declare (ignore ignore1 ignore2))
-               (let ((slot-name (eval slot-name-form)))
-                 (optimize-instance-access slots :read sparameter
-                                           slot-name nil)))))
-        ;; We don't return the optimized form directly, since there's
-        ;; still a chance that we'll find out later on that the
-        ;; optimization should not have been done, for example due to
-        ;; the walker encountering a SETQ on SPARAMETER later on in
-        ;; the body [ see for example clos.impure.lisp test with :name
-        ;; ((:setq :method-parameter) slot-value)) ]. Instead we defer
-        ;; the decision until the compiler macroexpands
-        ;; OPTIMIZED-SLOT-VALUE.
-        ;;
-        ;; Note that we must still call OPTIMIZE-INSTANCE-ACCESS at
-        ;; this point (instead of when expanding
-        ;; OPTIMIZED-SLOT-VALUE), since it mutates the structure of
-        ;; SLOTS. If that mutation isn't done during the walking,
-        ;; MAKE-METHOD-LAMBDA-INTERNAL won't wrap a correct PV-BINDING
-        ;; form around the body, and compilation will fail.  -- JES,
-        ;; 2006-09-18
-        `(optimized-slot-value ,form ,(car sparameter) ,optimized-form))
-      `(accessor-slot-value ,@(cdr form))))
+(defun optimize-slot-value (form slots required-parameters env)
+  (multiple-value-bind (sparameter slot-name)
+      (can-optimize-access form required-parameters env)
+    (if sparameter
+        (let ((optimized-form
+               (optimize-instance-access slots :read sparameter
+                                         slot-name nil)))
+             ;; We don't return the optimized form directly, since there's
+             ;; still a chance that we'll find out later on that the
+             ;; optimization should not have been done, for example due to
+             ;; the walker encountering a SETQ on SPARAMETER later on in
+             ;; the body [ see for example clos.impure.lisp test with :name
+             ;; ((:setq :method-parameter) slot-value)) ]. Instead we defer
+             ;; the decision until the compiler macroexpands
+             ;; OPTIMIZED-SLOT-VALUE.
+             ;;
+             ;; Note that we must still call OPTIMIZE-INSTANCE-ACCESS at
+             ;; this point (instead of when expanding
+             ;; OPTIMIZED-SLOT-VALUE), since it mutates the structure of
+             ;; SLOTS. If that mutation isn't done during the walking,
+             ;; MAKE-METHOD-LAMBDA-INTERNAL won't wrap a correct PV-BINDING
+             ;; form around the body, and compilation will fail.  -- JES,
+             ;; 2006-09-18
+             `(optimized-slot-value ,form ,(car sparameter) ,optimized-form))
+           `(accessor-slot-value ,@(cdr form)))))
 
 (defmacro optimized-slot-value (form parameter-name optimized-form
                                 &environment env)
       `(accessor-slot-value ,@(cdr form))
       optimized-form))
 
-(defun optimize-set-slot-value (slots sparameter form)
-  (if sparameter
-      (let ((optimized-form
-             (destructuring-bind (ignore1 ignore2 slot-name-form new-value) form
-               (declare (ignore ignore1 ignore2))
-               (let ((slot-name (eval slot-name-form)))
-                 (optimize-instance-access slots
-                                           :write
-                                           sparameter
-                                           slot-name
-                                           new-value)))))
-        ;; See OPTIMIZE-SLOT-VALUE
-        `(optimized-set-slot-value ,form ,(car sparameter) ,optimized-form))
-      `(accessor-set-slot-value ,@(cdr form))))
+(defun optimize-set-slot-value (form slots required-parameters env)
+  (multiple-value-bind (sparameter slot-name new-value)
+      (can-optimize-access form required-parameters env)
+    (if sparameter
+        (let ((optimized-form
+               (optimize-instance-access slots :write sparameter
+                                         slot-name new-value)))
+             ;; See OPTIMIZE-SLOT-VALUE
+             `(optimized-set-slot-value ,form ,(car sparameter) ,optimized-form))
+           `(accessor-set-slot-value ,@(cdr form)))))
 
 (defmacro optimized-set-slot-value (form parameter-name optimized-form
                                     &environment env)
         (t
          optimized-form)))
 
-(defun optimize-slot-boundp (slots sparameter form)
-  (if sparameter
-      (let ((optimized-form
-             (destructuring-bind
-                   ;; FIXME: In CMU CL ca. 19991205, this binding list
-                   ;; had a fourth element in it, NEW-VALUE. It's hard
-                   ;; to see how that could possibly be right, since
-                   ;; SLOT-BOUNDP has no NEW-VALUE. Since it was
-                   ;; causing a failure in building PCL for SBCL, so I
-                   ;; changed it to match the definition of
-                   ;; SLOT-BOUNDP (and also to match the list used in
-                   ;; the similar OPTIMIZE-SLOT-VALUE,
-                   ;; above). However, I'm weirded out by this, since
-                   ;; this is old code which has worked for ages to
-                   ;; build PCL for CMU CL, so it's hard to see why it
-                   ;; should need a patch like this in order to build
-                   ;; PCL for SBCL. I'd like to return to this and
-                   ;; find a test case which exercises this function
-                   ;; both in CMU CL, to see whether it's really a
-                   ;; previously-unexercised bug or whether I've
-                   ;; misunderstood something (and, presumably,
-                   ;; patched it wrong).
-                   (slot-boundp-symbol instance slot-name-form)
-                 form
-               (declare (ignore slot-boundp-symbol instance))
-               (let ((slot-name (eval slot-name-form)))
-                 (optimize-instance-access slots
-                                           :boundp
-                                           sparameter
-                                           slot-name
-                                           nil)))))
-        ;; See OPTIMIZE-SLOT-VALUE
-        `(optimized-slot-boundp ,form ,(car sparameter) ,optimized-form))
-      `(accessor-slot-boundp ,@(cdr form))))
+(defun optimize-slot-boundp (form slots required-parameters env)
+  (multiple-value-bind (sparameter slot-name)
+      (can-optimize-access form required-parameters env)
+    (if sparameter
+        (let ((optimized-form
+               (optimize-instance-access slots :boundp sparameter
+                                         slot-name nil)))
+          ;; See OPTIMIZE-SLOT-VALUE
+          `(optimized-slot-boundp ,form ,(car sparameter) ,optimized-form))
+        `(accessor-slot-boundp ,@(cdr form)))))
 
 (defmacro optimized-slot-boundp (form parameter-name optimized-form
                                  &environment env)
       (let* ((index (gensym))
              (value index))
         `(locally (declare #.*optimize-speed*)
-          (let ((,index (pvref ,pv ,pv-offset)))
+          (let ((,index (svref ,pv ,pv-offset)))
             (setq ,value (typecase ,index
                            ;; FIXME: the line marked by KLUDGE below
                            ;; (and the analogous spot in
       default
       (let* ((index (gensym)))
         `(locally (declare #.*optimize-speed*)
-          (let ((,index (pvref ,pv ,pv-offset)))
+          (let ((,index (svref ,pv ,pv-offset)))
             (typecase ,index
               ,@(when (or (null kind) (eq kind :instance))
                   `((fixnum (and ,slots
       default
       (let* ((index (gensym)))
         `(locally (declare #.*optimize-speed*)
-          (let ((,index (pvref ,pv ,pv-offset)))
+          (let ((,index (svref ,pv ,pv-offset)))
             (typecase ,index
               ,@(when (or (null kind) (eq kind :instance))
                   `((fixnum (not (and ,slots
     %method-lambda-list
     optimize
     ftype
+    muffle-conditions
     inline
     notinline))
 
          ;; The lambda-list used by BIND-ARGS
          (bind-list lambda-list)
          (setq-p (getf (cdr lmf-params) :setq-p))
+         (auxp (member '&aux bind-list))
          (call-next-method-p (getf (cdr lmf-params) :call-next-method-p)))
     ;; Try to use the normal function call machinery instead of BIND-ARGS
-    ;; bindings the arguments, unless:
+    ;; binding the arguments, unless:
     (unless (or ;; If all arguments are required, BIND-ARGS will be a no-op
                 ;; in any case.
-                (not restp)
+                (and (not restp) (not auxp))
                 ;; CALL-NEXT-METHOD wants to use BIND-ARGS, and needs a
                 ;; list of all non-required arguments.
                 call-next-method-p)
                          '.rest-arg.))
              (fmf-lambda-list (if rest-arg
                                   (append req-args (list '&rest rest-arg))
-                                  lambda-list)))
+                                  (if call-next-method-p
+                                      req-args
+                                      lambda-list))))
         `(list*
           :function
           (let* ((fmf (,(if (body-method-name body) 'named-lambda 'lambda)
                                    (method-function nm)
                                    nm)
                      :call-method-args (list nms)))))
-        (if restp
-            (let* ((rest (nthcdr nreq method-args))
-                   (args (ldiff method-args rest)))
-              (apply fmf pv-cell nmc (nconc args (list rest))))
-            (apply fmf pv-cell nmc method-args))))))
+        (apply fmf pv-cell nmc method-args)))))
 
 (defun get-pv-cell (method-args pv-table)
   (let ((pv-wrappers (pv-wrappers-from-all-args pv-table method-args)))