Simplify (and robustify) regular PACKing
[sbcl.git] / src / pcl / combin.lisp
index 759e710..8128f53 100644 (file)
             (if (listp method)
                 (early-method-function method)
                 (values nil (safe-method-fast-function method)))
-          (let* ((pv-table (and fmf (method-function-pv-table fmf))))
+          (let* ((pv-table (and fmf (method-plist-value method :pv-table))))
             (if (and fmf (or (null pv-table) wrappers))
                 (let* ((pv-wrappers (when pv-table
                                       (pv-wrappers-from-all-wrappers
                                        pv-table wrappers)))
-                       (pv-cell (when (and pv-table pv-wrappers)
-                                  (pv-table-lookup pv-table pv-wrappers))))
-                  (values mf t fmf pv-cell))
+                       (pv (when (and pv-table pv-wrappers)
+                             (pv-table-lookup pv-table pv-wrappers))))
+                  (values mf t fmf pv))
                 (values
                  (or mf (if (listp method)
-                            (setf (cadr method)
-                                  (method-function-from-fast-function fmf))
+                            (bug "early method with no method-function")
                             (method-function method)))
                  t nil nil)))))))
 
@@ -83,7 +82,7 @@
                           (early-method-function method)
                           (values nil (safe-method-fast-function method)))
                     (declare (ignore mf))
-                    (let* ((pv-table (and fmf (method-function-pv-table fmf))))
+                    (let* ((pv-table (and fmf (method-plist-value method :pv-table))))
                       (if (and fmf (or (null pv-table) wrappers-p))
                           'fast-method-call
                           'method-call))))
   ;; or aren't to prevent the leaky next methods bug.
   (let* ((cm-args (cdr form))
          (fmf-p (and (null no-fmf-p)
-                     (or (not (eq *boot-state* 'complete))
+                     (or (not (eq **boot-state** 'complete))
                          (gf-fast-method-function-p generic-function))
                      (null (cddr cm-args))))
          (method (car cm-args))
 
 (defun make-emf-from-method
     (method cm-args &optional gf fmf-p method-alist wrappers)
-  (multiple-value-bind (mf real-mf-p fmf pv-cell)
+  (multiple-value-bind (mf real-mf-p fmf pv)
       (get-method-function method method-alist wrappers)
     (if fmf
         (let* ((next-methods (car cm-args))
                       gf (car next-methods)
                       (list* (cdr next-methods) (cdr cm-args))
                       fmf-p method-alist wrappers))
-               (arg-info (method-function-get fmf :arg-info)))
-          (make-fast-method-call :function fmf
-                                 :pv-cell pv-cell
-                                 :next-method-call next
-                                 :arg-info arg-info))
+               (arg-info (method-plist-value method :arg-info))
+               (default (cons nil nil))
+               (value (method-plist-value method :constant-value default)))
+          (if (eq value default)
+              (make-fast-method-call :function fmf :pv pv
+                                     :next-method-call next :arg-info arg-info)
+              (make-constant-fast-method-call
+               :function fmf :pv pv :next-method-call next
+               :arg-info arg-info :value value)))
         (if real-mf-p
-            (make-method-call :function mf
-                              :call-method-args cm-args)
+            (flet ((frob-cm-arg (arg)
+                     (if (if (listp arg)
+                             (eq (car arg) :early-method)
+                             (method-p arg))
+                         arg
+                         (if (and (consp arg) (eq (car arg) 'make-method))
+                             (let ((emf (make-effective-method-function
+                                         gf (cadr arg) method-alist wrappers)))
+                               (etypecase emf
+                                 (method-call
+                                  (make-instance 'standard-method
+                                                 :specializers nil ; XXX
+                                                 :qualifiers nil ; XXX
+                                                 :function (method-call-function emf)))
+                                 (fast-method-call
+                                  (let* ((fmf (fast-method-call-function emf))
+                                         (fun (method-function-from-fast-method-call emf))
+                                         (mf (%make-method-function fmf nil)))
+                                    (set-funcallable-instance-function mf fun)
+                                    (make-instance 'standard-method
+                                                   :specializers nil ; XXX
+                                                   :qualifiers nil
+                                                   :function mf)))))
+                             arg))))
+              (let* ((default (cons nil nil))
+                     (value
+                      (method-plist-value method :constant-value default))
+                     ;; FIXME: this is wrong.  Very wrong.  It assumes
+                     ;; that the only place that can have make-method
+                     ;; calls is in the list structure of the second
+                     ;; argument to CALL-METHOD, but AMOP says that
+                     ;; CALL-METHOD can be more complicated if
+                     ;; COMPUTE-EFFECTIVE-METHOD (and presumably
+                     ;; MAKE-METHOD-LAMBDA) is adjusted to match.
+                     ;;
+                     ;; On the other hand, it's a start, because
+                     ;; without this calls to MAKE-METHOD in method
+                     ;; combination where one of the methods is of a
+                     ;; user-defined class don't work at all.  -- CSR,
+                     ;; 2006-08-05
+                     (args (cons (mapcar #'frob-cm-arg (car cm-args))
+                                 (cdr cm-args))))
+                (if (eq value default)
+                    (make-method-call :function mf :call-method-args args)
+                    (make-constant-method-call :function mf :value value
+                                               :call-method-args args))))
             mf))))
 
 (defun make-effective-method-function-simple1
 
 (defun expand-effective-method-function (gf effective-method &optional env)
   (declare (ignore env))
-  (multiple-value-bind (nreq applyp metatypes nkeys arg-info)
+  (multiple-value-bind (nreq applyp)
       (get-generic-fun-info gf)
-    (declare (ignore nreq nkeys arg-info))
-    (let ((ll (make-fast-method-call-lambda-list metatypes applyp))
+    (let ((ll (make-fast-method-call-lambda-list nreq applyp))
           (check-applicable-keywords
            (when (and applyp (gf-requires-emf-keyword-checks gf))
              '((check-applicable-keywords))))
           (error-p (or (eq (first effective-method) '%no-primary-method)
                        (eq (first effective-method) '%invalid-qualifiers)))
           (mc-args-p
-           (when (eq *boot-state* 'complete)
+           (when (eq **boot-state** 'complete)
              ;; Otherwise the METHOD-COMBINATION slot is not bound.
              (let ((combin (generic-function-method-combination gf)))
                (and (long-method-combination-p combin)
-                    (long-method-combination-args-lambda-list combin))))))
+                    (long-method-combination-args-lambda-list combin)))))
+          (name `(emf ,(generic-function-name gf))))
       (cond
         (error-p
-         `(lambda (.pv-cell. .next-method-call. &rest .args.)
-           (declare (ignore .pv-cell. .next-method-call.))
-           (declare (ignorable .args.))
-           (flet ((%no-primary-method (gf args)
-                    (apply #'no-primary-method gf args))
-                  (%invalid-qualifiers (gf combin method)
-                    (invalid-qualifiers gf combin method)))
-             (declare (ignorable #'%no-primary-method #'%invalid-qualifiers))
-             ,effective-method)))
+         `(named-lambda ,name (.pv. .next-method-call. &rest .args.)
+            (declare (ignore .pv. .next-method-call.))
+            (declare (ignorable .args.))
+            (flet ((%no-primary-method (gf args)
+                     (call-no-primary-method gf args))
+                   (%invalid-qualifiers (gf combin method)
+                     (invalid-qualifiers gf combin method)))
+              (declare (ignorable #'%no-primary-method #'%invalid-qualifiers))
+              ,effective-method)))
         (mc-args-p
-         (let* ((required
-                 ;; FIXME: Ick. Shared idiom, too, with stuff in cache.lisp
-                 (let (req)
-                   (dotimes (i (length metatypes) (nreverse req))
-                     (push (dfun-arg-symbol i) req))))
+         (let* ((required (make-dfun-required-args nreq))
                 (gf-args (if applyp
-                             `(list* ,@required .dfun-rest-arg.)
+                             `(list* ,@required
+                                     (sb-c::%listify-rest-args
+                                      .dfun-more-context.
+                                      (the (and unsigned-byte fixnum)
+                                        .dfun-more-count.)))
                              `(list ,@required))))
-           `(lambda ,ll
-             (declare (ignore .pv-cell. .next-method-call.))
-             (let ((.gf-args. ,gf-args))
-               (declare (ignorable .gf-args.))
-               ,@check-applicable-keywords
-               ,effective-method))))
+           `(named-lambda ,name ,ll
+              (declare (ignore .pv. .next-method-call.))
+              (let ((.gf-args. ,gf-args))
+                (declare (ignorable .gf-args.))
+                ,@check-applicable-keywords
+                ,effective-method))))
         (t
-         `(lambda ,ll
-           (declare (ignore ,@(if error-p ll '(.pv-cell. .next-method-call.))))
-           ,@check-applicable-keywords
-           ,effective-method))))))
+         `(named-lambda ,name ,ll
+            (declare (ignore ,@(if error-p ll '(.pv. .next-method-call.))))
+            ,@check-applicable-keywords
+            ,effective-method))))))
 
 (defun expand-emf-call-method (gf form metatypes applyp env)
   (declare (ignore gf metatypes applyp env))
     (call-method
      (let ((gensym (get-effective-method-gensym)))
        (values (make-emf-call
-                metatypes applyp gensym
+                (length metatypes) applyp gensym
                 (make-effective-method-fun-type
                  generic-function form method-alist-p wrappers-p))
                (list gensym))))
            (type (make-effective-method-list-fun-type
                   generic-function form method-alist-p wrappers-p)))
        (values `(dolist (emf ,gensym nil)
-                 ,(make-emf-call metatypes applyp 'emf type))
+                 ,(make-emf-call (length metatypes) applyp 'emf type))
                (list gensym))))
     (check-applicable-keywords
-     (values `(check-applicable-keywords
-               .dfun-rest-arg. .keyargs-start. .valid-keys.)
+     (values `(check-applicable-keywords .keyargs-start.
+                                         .valid-keys.
+                                         .dfun-more-context.
+                                         .dfun-more-count.)
              '(.keyargs-start. .valid-keys.)))
-
     (t
      (default-code-converter form))))
 
 (defun gf-requires-emf-keyword-checks (generic-function)
   (member '&key (gf-lambda-list generic-function)))
 
-(defvar *in-precompute-effective-methods-p* nil)
-
 (defun standard-compute-effective-method
     (generic-function combin applicable-methods)
   (collect ((before) (primary) (after) (around))
-    (flet ((invalid (gf combin m)
-             (if *in-precompute-effective-methods-p*
-                 (return-from standard-compute-effective-method
-                   `(%invalid-qualifiers ',gf ',combin ',m))
-                 (invalid-qualifiers gf combin m))))
+    (flet ((invalid (gf combin m) (invalid-qualifiers gf combin m)))
       (dolist (m applicable-methods)
         (let ((qualifiers (if (listp m)
                               (early-method-qualifiers m)
-                              (method-qualifiers m))))
+                              (safe-method-qualifiers m))))
           (cond
             ((null qualifiers) (primary m))
             ((cdr qualifiers) (invalid generic-function combin m))
         (aver any-keyp)
         (values (if allowp t keys) nopt)))))
 
-(defun check-applicable-keywords (args start valid-keys)
+(defun check-applicable-keywords (start valid-keys more-context more-count)
   (let ((allow-other-keys-seen nil)
         (allow-other-keys nil)
-        (args (nthcdr start args)))
-    (collect ((invalid))
-      (loop
-       (when (null args)
-         (when (and (invalid) (not allow-other-keys))
-           (error 'simple-program-error
-                  :format-control "~@<invalid keyword argument~P: ~
+        (i start))
+    (declare (type index i more-count)
+             (optimize speed))
+    (flet ((current-value ()
+             (sb-c::%more-arg more-context i)))
+      (declare (inline current-value))
+      (collect ((invalid))
+        (loop
+           (when (>= i more-count)
+             (when (and (invalid) (not allow-other-keys))
+               (error 'simple-program-error
+                      :format-control "~@<invalid keyword argument~P: ~
                                    ~{~S~^, ~} (valid keys are ~{~S~^, ~}).~@:>"
-                  :format-arguments (list (length (invalid)) (invalid) valid-keys)))
-         (return))
-       (let ((key (pop args)))
-         (cond
-           ((not (symbolp key))
-            (error 'simple-program-error
-                   :format-control "~@<keyword argument not a symbol: ~S.~@:>"
-                   :format-arguments (list key)))
-           ((null args) (sb-c::%odd-key-args-error))
-           ((eq key :allow-other-keys)
-            ;; only the leftmost :ALLOW-OTHER-KEYS has any effect
-            (unless allow-other-keys-seen
-              (setq allow-other-keys-seen t
-                    allow-other-keys (car args))))
-           ((eq t valid-keys))
-           ((not (memq key valid-keys)) (invalid key))))
-       (pop args)))))
+                      :format-arguments (list (length (invalid)) (invalid) valid-keys)))
+             (return))
+           (let ((key (current-value)))
+             (incf i)
+             (cond
+               ((not (symbolp key))
+                (error 'simple-program-error
+                       :format-control "~@<keyword argument not a symbol: ~S.~@:>"
+                       :format-arguments (list key)))
+               ((= i more-count)
+                (sb-c::%odd-key-args-error))
+               ((eq key :allow-other-keys)
+                ;; only the leftmost :ALLOW-OTHER-KEYS has any effect
+                (unless allow-other-keys-seen
+                  (setq allow-other-keys-seen t
+                        allow-other-keys (current-value))))
+               ((eq t valid-keys))
+               ((not (memq key valid-keys)) (invalid key))))
+           (incf i))))))
 \f
 ;;;; the STANDARD method combination type. This is coded by hand
 ;;;; (rather than with DEFINE-METHOD-COMBINATION) for bootstrapping