X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fpcl%2Fboot.lisp;h=3051e17eac41a4596f0f5760f279f92efc67f709;hb=6049dd2bf3dfe37080a30a4a751076c1254030bd;hp=5d4f9404d22b991766268d9be38eaca9503431c6;hpb=fcbf5a7338a1600a6a05bc8be7b42be43505d1dc;p=sbcl.git diff --git a/src/pcl/boot.lisp b/src/pcl/boot.lisp index 5d4f940..3051e17 100644 --- a/src/pcl/boot.lisp +++ b/src/pcl/boot.lisp @@ -388,16 +388,14 @@ bootstrapping. (if proto-method (class-name (class-of proto-method)) 'standard-method) - initargs-form - (getf (getf initargs :plist) - :pv-table-symbol))))))) + initargs-form)))))) (defun interned-symbol-p (x) (and (symbolp x) (symbol-package x))) -(defun make-defmethod-form (name qualifiers specializers - unspecialized-lambda-list method-class-name - initargs-form &optional pv-table-symbol) +(defun make-defmethod-form + (name qualifiers specializers unspecialized-lambda-list + method-class-name initargs-form) (let (fn fn-lambda) (if (and (interned-symbol-p (fun-name-block-name name)) @@ -415,7 +413,7 @@ bootstrapping. specializers) (consp initargs-form) (eq (car initargs-form) 'list*) - (memq (cadr initargs-form) '(:function :fast-function)) + (memq (cadr initargs-form) '(:function)) (consp (setq fn (caddr initargs-form))) (eq (car fn) 'function) (consp (setq fn-lambda (cadr fn))) @@ -436,8 +434,7 @@ bootstrapping. unspecialized-lambda-list method-class-name `(list* ,(cadr initargs-form) #',mname - ,@(cdddr initargs-form)) - pv-table-symbol))) + ,@(cdddr initargs-form))))) (make-defmethod-form-internal name qualifiers `(list ,@(mapcar (lambda (specializer) @@ -448,12 +445,11 @@ bootstrapping. specializers)) unspecialized-lambda-list method-class-name - initargs-form - pv-table-symbol)))) + initargs-form)))) (defun make-defmethod-form-internal (name qualifiers specializers-form unspecialized-lambda-list - method-class-name initargs-form &optional pv-table-symbol) + method-class-name initargs-form) `(load-defmethod ',method-class-name ',name @@ -461,11 +457,6 @@ bootstrapping. ,specializers-form ',unspecialized-lambda-list ,initargs-form - ;; Paper over a bug in KCL by passing the cache-symbol here in - ;; addition to in the list. FIXME: We should no longer need to do - ;; this, since the CLOS code is now SBCL-specific, and doesn't - ;; need to be ported to every buggy compiler in existence. - ',pv-table-symbol (sb-c:source-location))) (defmacro make-method-function (method-lambda &environment env) @@ -582,7 +573,7 @@ bootstrapping. ;; SB-KERNEL:INSTANCE. In an effort to sweep such ;; problems under the rug, we exclude these problem ;; cases by blacklisting them here. -- WHN 2001-01-19 - '(slot-object)) + (list 'slot-object #+nil (find-class 'slot-object))) '(ignorable)) ((not (eq *boot-state* 'complete)) ;; KLUDGE: PCL, in its wisdom, sometimes calls methods with @@ -591,6 +582,8 @@ bootstrapping. ;; second argument.) Hopefully it only does this kind of ;; weirdness when bootstrapping.. -- WHN 20000610 '(ignorable)) + ((typep specializer 'eql-specializer) + `(type (eql ,(eql-specializer-object specializer)) ,parameter)) ((var-globally-special-p parameter) ;; KLUDGE: Don't declare types for global special variables ;; -- our rebinding magic for SETQ cases don't work right @@ -604,39 +597,65 @@ bootstrapping. '(ignorable)) (t ;; Otherwise, we can usually make Python very happy. - (let ((kind (info :type :kind specializer))) - (ecase kind - ((:primitive) `(type ,specializer ,parameter)) - ((:defined) - (let ((class (find-class specializer nil))) - ;; CLASS can be null here if the user has erroneously - ;; tried to use a defined type as a specializer; it - ;; can be a non-BUILT-IN-CLASS if the user defines a - ;; type and calls (SETF FIND-CLASS) in a consistent - ;; way. - (when (and class (typep class 'built-in-class)) - `(type ,specializer ,parameter)))) - ((:instance nil) - (let ((class (find-class specializer nil))) - (cond - (class - (if (typep class '(or built-in-class structure-class)) - `(type ,specializer ,parameter) - ;; don't declare CLOS classes as parameters; - ;; it's too expensive. - '(ignorable))) - (t - ;; we can get here, and still not have a failure - ;; case, by doing MOP programming like (PROGN - ;; (ENSURE-CLASS 'FOO) (DEFMETHOD BAR ((X FOO)) - ;; ...)). Best to let the user know we haven't - ;; been able to extract enough information: - (style-warn - "~@" - specializer - 'parameter-specializer-declaration-in-defmethod) - '(ignorable))))) - ((:forthcoming-defclass-type) '(ignorable))))))) + ;; + ;; KLUDGE: Since INFO doesn't work right for class objects here, + ;; and they are valid specializers, see if the specializer is + ;; a named class, and use the name in that case -- otherwise + ;; the class instance is ok, since info will just return NIL, NIL. + ;; + ;; We still need to deal with the class case too, but at + ;; least #.(find-class 'integer) and integer as equivalent + ;; specializers with this. + (let* ((specializer (if (and (typep specializer 'class) + (let ((name (class-name specializer))) + (and name (symbolp name) + (eq specializer (find-class name nil))))) + (class-name specializer) + specializer)) + (kind (info :type :kind specializer))) + + (flet ((specializer-class () + (if (typep specializer 'class) + specializer + (find-class specializer nil)))) + (ecase kind + ((:primitive) `(type ,specializer ,parameter)) + ((:defined) + (let ((class (specializer-class))) + ;; CLASS can be null here if the user has erroneously + ;; tried to use a defined type as a specializer; it + ;; can be a non-BUILT-IN-CLASS if the user defines a + ;; type and calls (SETF FIND-CLASS) in a consistent + ;; way. + (when (and class (typep class 'built-in-class)) + `(type ,specializer ,parameter)))) + ((:instance nil) + (let ((class (specializer-class))) + (cond + (class + (if (typep class '(or built-in-class structure-class)) + `(type ,specializer ,parameter) + ;; don't declare CLOS classes as parameters; + ;; it's too expensive. + '(ignorable))) + (t + ;; we can get here, and still not have a failure + ;; case, by doing MOP programming like (PROGN + ;; (ENSURE-CLASS 'FOO) (DEFMETHOD BAR ((X FOO)) + ;; ...)). Best to let the user know we haven't + ;; been able to extract enough information: + (style-warn + "~@" + specializer + 'parameter-specializer-declaration-in-defmethod) + '(ignorable))))) + ((:forthcoming-defclass-type) + '(ignorable)))))))) + +;;; For passing a list (groveled by the walker) of the required +;;; parameters whose bindings are modified in the method body to the +;;; optimized-slot-value* macros. +(define-symbol-macro %parameter-binding-modified ()) (defun make-method-lambda-internal (method-lambda &optional env) (unless (and (consp method-lambda) (eq (car method-lambda) 'lambda)) @@ -727,7 +746,8 @@ bootstrapping. (return nil)))))) (multiple-value-bind (walked-lambda call-next-method-p closurep - next-method-p-p setq-p) + next-method-p-p setq-p + parameters-setqd) (walk-method-lambda method-lambda required-parameters env @@ -738,24 +758,23 @@ bootstrapping. walked-documentation) (parse-body (cddr walked-lambda)) (declare (ignore walked-documentation)) - (when (or next-method-p-p call-next-method-p) - (setq plist (list* :needs-next-methods-p t plist))) (when (some #'cdr slots) (multiple-value-bind (slot-name-lists call-list) (slot-name-lists-from-slots slots calls) - (let ((pv-table-symbol (make-symbol "pv-table"))) - (setq plist - `(,@(when slot-name-lists - `(:slot-name-lists ,slot-name-lists)) - ,@(when call-list - `(:call-list ,call-list)) - :pv-table-symbol ,pv-table-symbol - ,@plist)) - (setq walked-lambda-body - `((pv-binding (,required-parameters - ,slot-name-lists - ,pv-table-symbol) - ,@walked-lambda-body)))))) + (setq plist + `(,@(when slot-name-lists + `(:slot-name-lists ,slot-name-lists)) + ,@(when call-list + `(:call-list ,call-list)) + ,@plist)) + (setq walked-lambda-body + `((pv-binding (,required-parameters + ,slot-name-lists + (load-time-value + (intern-pv-table + :slot-name-lists ',slot-name-lists + :call-list ',call-list))) + ,@walked-lambda-body))))) (when (and (memq '&key lambda-list) (not (memq '&allow-other-keys lambda-list))) (let ((aux (memq '&aux lambda-list))) @@ -780,9 +799,16 @@ bootstrapping. :closurep ,closurep :applyp ,applyp) ,@walked-declarations - ,@walked-lambda-body)) + (locally + (declare (disable-package-locks + %parameter-binding-modified)) + (symbol-macrolet ((%parameter-binding-modified + ',@parameters-setqd)) + (declare (enable-package-locks + %parameter-binding-modified)) + ,@walked-lambda-body)))) `(,@(when plist - `(:plist ,plist)) + `(plist ,plist)) ,@(when documentation `(:documentation ,documentation))))))))))) @@ -861,6 +887,8 @@ bootstrapping. (defstruct (method-call (:copier nil)) (function #'identity :type function) call-method-args) +(defstruct (constant-method-call (:copier nil) (:include method-call)) + value) #-sb-fluid (declaim (sb-ext:freeze-type method-call)) @@ -884,6 +912,9 @@ bootstrapping. pv-cell next-method-call arg-info) +(defstruct (constant-fast-method-call + (:copier nil) (:include fast-method-call)) + value) #-sb-fluid (declaim (sb-ext:freeze-type fast-method-call)) @@ -949,58 +980,70 @@ bootstrapping. (trace-emf-call ,emf ,restp (list ,@required-args+rest-arg)) (invoke-fast-method-call ,emf ,@required-args+rest-arg))) -(defmacro invoke-effective-method-function (emf restp - &rest required-args+rest-arg) - (unless (constantp restp) - (error "The RESTP argument is not constant.")) - ;; FIXME: The RESTP handling here is confusing and maybe slightly - ;; broken if RESTP evaluates to a non-self-evaluating form. E.g. if - ;; (INVOKE-EFFECTIVE-METHOD-FUNCTION EMF '(ERROR "gotcha") ...) - ;; then TRACE-EMF-CALL-CALL-INTERNAL might die on a gotcha error. - (setq restp (constant-form-value restp)) - `(progn - (trace-emf-call ,emf ,restp (list ,@required-args+rest-arg)) - (cond ((typep ,emf 'fast-method-call) - (invoke-fast-method-call ,emf ,@required-args+rest-arg)) - ;; "What," you may wonder, "do these next two clauses do?" - ;; In that case, you are not a PCL implementor, for they - ;; considered this to be self-documenting.:-| Or CSR, for - ;; that matter, since he can also figure it out by looking - ;; at it without breaking stride. For the rest of us, - ;; though: From what the code is doing with .SLOTS. and - ;; whatnot, evidently it's implementing SLOT-VALUEish and - ;; GET-SLOT-VALUEish things. Then we can reason backwards - ;; and conclude that setting EMF to a FIXNUM is an - ;; optimized way to represent these slot access operations. - ,@(when (and (null restp) (= 1 (length required-args+rest-arg))) - `(((typep ,emf 'fixnum) - (let* ((.slots. (get-slots-or-nil - ,(car required-args+rest-arg))) - (value (when .slots. (clos-slots-ref .slots. ,emf)))) - (if (eq value +slot-unbound+) - (slot-unbound-internal ,(car required-args+rest-arg) - ,emf) - value))))) - ,@(when (and (null restp) (= 2 (length required-args+rest-arg))) - `(((typep ,emf 'fixnum) - (let ((.new-value. ,(car required-args+rest-arg)) - (.slots. (get-slots-or-nil - ,(cadr required-args+rest-arg)))) - (when .slots. - (setf (clos-slots-ref .slots. ,emf) .new-value.)))))) - ;; (In cmucl-2.4.8 there was a commented-out third ,@(WHEN - ;; ...) clause here to handle SLOT-BOUNDish stuff. Since - ;; there was no explanation and presumably the code is 10+ - ;; years stale, I simply deleted it. -- WHN) - (t - (etypecase ,emf - (method-call - (invoke-method-call ,emf ,restp ,@required-args+rest-arg)) - (function - ,(if restp - `(apply (the function ,emf) ,@required-args+rest-arg) - `(funcall (the function ,emf) - ,@required-args+rest-arg)))))))) +(defun effective-method-optimized-slot-access-clause + (emf restp required-args+rest-arg) + ;; "What," you may wonder, "do these next two clauses do?" In that + ;; case, you are not a PCL implementor, for they considered this to + ;; be self-documenting.:-| Or CSR, for that matter, since he can + ;; also figure it out by looking at it without breaking stride. For + ;; the rest of us, though: From what the code is doing with .SLOTS. + ;; and whatnot, evidently it's implementing SLOT-VALUEish and + ;; GET-SLOT-VALUEish things. Then we can reason backwards and + ;; conclude that setting EMF to a FIXNUM is an optimized way to + ;; represent these slot access operations. + (when (not restp) + (let ((length (length required-args+rest-arg))) + (cond ((= 1 length) + `((fixnum + (let* ((.slots. (get-slots-or-nil + ,(car required-args+rest-arg))) + (value (when .slots. (clos-slots-ref .slots. ,emf)))) + (if (eq value +slot-unbound+) + (slot-unbound-internal ,(car required-args+rest-arg) + ,emf) + value))))) + ((= 2 length) + `((fixnum + (let ((.new-value. ,(car required-args+rest-arg)) + (.slots. (get-slots-or-nil + ,(cadr required-args+rest-arg)))) + (when .slots. + (setf (clos-slots-ref .slots. ,emf) .new-value.))))))) + ;; (In cmucl-2.4.8 there was a commented-out third ,@(WHEN + ;; ...) clause here to handle SLOT-BOUNDish stuff. Since + ;; there was no explanation and presumably the code is 10+ + ;; years stale, I simply deleted it. -- WHN) + ))) + +;;; Before SBCL 0.9.16.7 instead of +;;; INVOKE-NARROW-EFFECTIVE-METHOD-FUNCTION we passed a (THE (OR +;;; FUNCTION METHOD-CALL FAST-METHOD-CALL) EMF) form as the EMF. Now, +;;; to make less work for the compiler we take a path that doesn't +;;; involve the slot-accessor clause (where EMF is a FIXNUM) at all. +(macrolet ((def (name &optional narrow) + `(defmacro ,name (emf restp &rest required-args+rest-arg) + (unless (constantp restp) + (error "The RESTP argument is not constant.")) + (setq restp (constant-form-value restp)) + (with-unique-names (emf-n) + `(locally + (declare (optimize (sb-c:insert-step-conditions 0))) + (let ((,emf-n ,emf)) + (trace-emf-call ,emf-n ,restp (list ,@required-args+rest-arg)) + (etypecase ,emf-n + (fast-method-call + (invoke-fast-method-call ,emf-n ,@required-args+rest-arg)) + ,@,(unless narrow + `(effective-method-optimized-slot-access-clause + emf-n restp required-args+rest-arg)) + (method-call + (invoke-method-call ,emf-n ,restp ,@required-args+rest-arg)) + (function + ,(if restp + `(apply ,emf-n ,@required-args+rest-arg) + `(funcall ,emf-n ,@required-args+rest-arg)))))))))) + (def invoke-effective-method-function nil) + (def invoke-narrow-effective-method-function t)) (defun invoke-emf (emf args) (trace-emf-call emf t args) @@ -1072,35 +1115,12 @@ bootstrapping. (apply emf args)))) -(defmacro fast-narrowed-emf (emf) - ;; INVOKE-EFFECTIVE-METHOD-FUNCTION has code in it to dispatch on - ;; the possibility that EMF might be of type FIXNUM (as an optimized - ;; representation of a slot accessor). But as far as I (WHN - ;; 2002-06-11) can tell, it's impossible for such a representation - ;; to end up as .NEXT-METHOD-CALL. By reassuring INVOKE-E-M-F that - ;; when called from this context it needn't worry about the FIXNUM - ;; case, we can keep those cases from being compiled, which is good - ;; both because it saves bytes and because it avoids annoying type - ;; mismatch compiler warnings. - ;; - ;; KLUDGE: In sbcl-0.7.4.29, the compiler's type system isn't smart - ;; enough about NOT and intersection types to benefit from a (NOT - ;; FIXNUM) declaration here. -- WHN 2002-06-12 (FIXME: maybe it is - ;; now... -- CSR, 2003-06-07) - ;; - ;; FIXME: Might the FUNCTION type be omittable here, leaving only - ;; METHOD-CALLs? Failing that, could this be documented somehow? - ;; (It'd be nice if the types involved could be understood without - ;; solving the halting problem.) - `(the (or function method-call fast-method-call) - ,emf)) - (defmacro fast-call-next-method-body ((args next-method-call rest-arg) method-name-declaration cnm-args) `(if ,next-method-call - ,(let ((call `(invoke-effective-method-function - (fast-narrowed-emf ,next-method-call) + ,(let ((call `(invoke-narrow-effective-method-function + ,next-method-call ,(not (null rest-arg)) ,@args ,@(when rest-arg `(,rest-arg))))) @@ -1134,7 +1154,8 @@ bootstrapping. ,@body) `(flet (,@(when call-next-method-p `((call-next-method (&rest cnm-args) - (declare (muffle-conditions code-deletion-note)) + (declare (muffle-conditions code-deletion-note) + (optimize (sb-c:insert-step-conditions 0))) ,@(if (safe-code-p env) `((%check-cnm-args cnm-args (list ,@args) ',method-name-declaration)) @@ -1145,8 +1166,8 @@ bootstrapping. ,method-name-declaration cnm-args)))) ,@(when next-method-p-p - `((next-method-p - () + `((next-method-p () + (declare (optimize (sb-c:insert-step-conditions 0))) (not (null ,next-method-call)))))) (let ,rebindings ,@(when rebindings `((declare (ignorable ,@all-params)))) @@ -1265,13 +1286,18 @@ bootstrapping. return tail)) (defun walk-method-lambda (method-lambda required-parameters env slots calls) - (let ((call-next-method-p nil) ; flag indicating that CALL-NEXT-METHOD - ; should be in the method definition - (closurep nil) ; flag indicating that #'CALL-NEXT-METHOD - ; was seen in the body of a method - (next-method-p-p nil) ; flag indicating that NEXT-METHOD-P - ; should be in the method definition - (setq-p nil)) + (let (;; flag indicating that CALL-NEXT-METHOD should be in the + ;; method definition + (call-next-method-p nil) + ;; flag indicating that #'CALL-NEXT-METHOD was seen in the + ;; body of a method + (closurep nil) + ;; flag indicating that NEXT-METHOD-P should be in the method + ;; definition + (next-method-p-p nil) + ;; a list of all required parameters whose bindings might be + ;; modified in the method body. + (parameters-setqd nil)) (flet ((walk-function (form context env) (cond ((not (eq context :eval)) form) ;; FIXME: Jumping to a conclusion from the way it's used @@ -1295,7 +1321,34 @@ bootstrapping. ;; force method doesn't really cost much; a little ;; loss of discrimination over IGNORED variables ;; should be all. -- CSR, 2004-07-01 - (setq setq-p t) + ;; + ;; As of 2006-09-18 modified parameter bindings + ;; are now tracked with more granularity than just + ;; one SETQ-P flag, in order to disable SLOT-VALUE + ;; optimizations for parameters that are SETQd. + ;; The old binary SETQ-P flag is still used for + ;; all other purposes, since as noted above, the + ;; extra cost is minimal. -- JES, 2006-09-18 + ;; + ;; The walker will split (SETQ A 1 B 2) to + ;; separate (SETQ A 1) and (SETQ B 2) forms, so we + ;; only need to handle the simple case of SETQ + ;; here. + (let ((vars (if (eq (car form) 'setq) + (list (second form)) + (second form)))) + (dolist (var vars) + ;; Note that we don't need to check for + ;; %VARIABLE-REBINDING declarations like is + ;; done in CAN-OPTIMIZE-ACCESS1, since the + ;; bindings that will have that declation will + ;; never be SETQd. + (when (var-declaration '%class var env) + ;; If a parameter binding is shadowed by + ;; another binding it won't have a %CLASS + ;; declaration anymore, and this won't get + ;; executed. + (pushnew var parameters-setqd)))) form) ((and (eq (car form) 'function) (cond ((eq (cadr form) 'call-next-method) @@ -1310,9 +1363,9 @@ bootstrapping. ((and (memq (car form) '(slot-value set-slot-value slot-boundp)) (constantp (caddr form))) - (let ((parameter (can-optimize-access form - required-parameters - env))) + (let ((parameter (can-optimize-access form + required-parameters + env))) (let ((fun (ecase (car form) (slot-value #'optimize-slot-value) (set-slot-value #'optimize-set-slot-value) @@ -1334,7 +1387,8 @@ bootstrapping. call-next-method-p closurep next-method-p-p - setq-p))))) + (not (null parameters-setqd)) + parameters-setqd))))) (defun generic-function-name-p (name) (and (legal-fun-name-p name) @@ -1343,74 +1397,29 @@ bootstrapping. (standard-generic-function-p (gdefinition name)) (funcallable-instance-p (gdefinition name))))) -(defvar *method-function-plist* (make-hash-table :test 'eq)) -(defvar *mf1* nil) -(defvar *mf1p* nil) -(defvar *mf1cp* nil) -(defvar *mf2* nil) -(defvar *mf2p* nil) -(defvar *mf2cp* nil) - -(defun method-function-plist (method-function) - (unless (eq method-function *mf1*) - (rotatef *mf1* *mf2*) - (rotatef *mf1p* *mf2p*) - (rotatef *mf1cp* *mf2cp*)) - (unless (or (eq method-function *mf1*) (null *mf1cp*)) - (setf (gethash *mf1* *method-function-plist*) *mf1p*)) - (unless (eq method-function *mf1*) - (setf *mf1* method-function - *mf1cp* nil - *mf1p* (gethash method-function *method-function-plist*))) - *mf1p*) - -(defun (setf method-function-plist) - (val method-function) - (unless (eq method-function *mf1*) - (rotatef *mf1* *mf2*) - (rotatef *mf1cp* *mf2cp*) - (rotatef *mf1p* *mf2p*)) - (unless (or (eq method-function *mf1*) (null *mf1cp*)) - (setf (gethash *mf1* *method-function-plist*) *mf1p*)) - (setf *mf1* method-function - *mf1cp* t - *mf1p* val)) - -(defun method-function-get (method-function key &optional default) - (getf (method-function-plist method-function) key default)) - -(defun (setf method-function-get) - (val method-function key) - (setf (getf (method-function-plist method-function) key) val)) - -(defun method-function-pv-table (method-function) - (method-function-get method-function :pv-table)) - -(defun method-function-method (method-function) - (method-function-get method-function :method)) - -(defun method-function-needs-next-methods-p (method-function) - (method-function-get method-function :needs-next-methods-p t)) +(defun method-plist-value (method key &optional default) + (let ((plist (if (consp method) + (getf (early-method-initargs method) 'plist) + (object-plist method)))) + (getf plist key default))) + +(defun (setf method-plist-value) (new-value method key &optional default) + (if (consp method) + (setf (getf (getf (early-method-initargs method) 'plist) key default) + new-value) + (setf (getf (object-plist method) key default) new-value))) -(defmacro method-function-closure-generator (method-function) - `(method-function-get ,method-function 'closure-generator)) - (defun load-defmethod - (class name quals specls ll initargs pv-table-symbol source-location) + (class name quals specls ll initargs source-location) (setq initargs (copy-tree initargs)) - (let ((method-spec (or (getf initargs :method-spec) - (make-method-spec name quals specls)))) - (setf (getf initargs :method-spec) method-spec) - (load-defmethod-internal class name quals specls - ll initargs pv-table-symbol - source-location))) + (setf (getf (getf initargs 'plist) :name) + (make-method-spec name quals specls)) + (load-defmethod-internal class name quals specls + ll initargs source-location)) (defun load-defmethod-internal (method-class gf-spec qualifiers specializers lambda-list - initargs pv-table-symbol source-location) - (when pv-table-symbol - (setf (getf (getf initargs :plist) :pv-table-symbol) - pv-table-symbol)) + initargs source-location) (when (and (eq *boot-state* 'complete) (fboundp gf-spec)) (let* ((gf (fdefinition gf-spec)) @@ -1443,40 +1452,25 @@ bootstrapping. (defun make-method-spec (gf-spec qualifiers unparsed-specializers) `(slow-method ,gf-spec ,@qualifiers ,unparsed-specializers)) -(defun initialize-method-function (initargs &optional return-function-p method) +(defun initialize-method-function (initargs method) (let* ((mf (getf initargs :function)) - (method-spec (getf initargs :method-spec)) - (plist (getf initargs :plist)) - (pv-table-symbol (getf plist :pv-table-symbol)) - (pv-table nil) - (mff (getf initargs :fast-function))) - (flet ((set-mf-property (p v) - (when mf - (setf (method-function-get mf p) v)) - (when mff - (setf (method-function-get mff p) v)))) - (when method-spec - (when mf - (setq mf (set-fun-name mf method-spec))) - (when mff - (let ((name `(fast-method ,@(cdr method-spec)))) - (set-fun-name mff name) - (unless mf - (set-mf-property :name name))))) - (when plist + (mff (and (typep mf '%method-function) + (%method-function-fast-function mf))) + (plist (getf initargs 'plist)) + (name (getf plist :name))) + (when name + (when mf + (setq mf (set-fun-name mf name))) + (when (and mff (consp name) (eq (car name) 'slow-method)) + (let ((fast-name `(fast-method ,@(cdr name)))) + (set-fun-name mff fast-name)))) + (when plist + (let ((plist plist)) (let ((snl (getf plist :slot-name-lists)) (cl (getf plist :call-list))) (when (or snl cl) - (setq pv-table (intern-pv-table :slot-name-lists snl - :call-list cl)) - (when pv-table (set pv-table-symbol pv-table)) - (set-mf-property :pv-table pv-table))) - (loop (when (null plist) (return nil)) - (set-mf-property (pop plist) (pop plist))) - (when method - (set-mf-property :method method)) - (when return-function-p - (or mf (method-function-from-fast-function mff))))))) + (setf (method-plist-value method :pv-table) + (intern-pv-table :slot-name-lists snl :call-list cl)))))))) (defun analyze-lambda-list (lambda-list) (flet (;; FIXME: Is this redundant with SB-C::MAKE-KEYWORD-FOR-ARG? @@ -1754,10 +1748,10 @@ bootstrapping. (defvar *sm-specializers-index* (!bootstrap-slot-index 'standard-method 'specializers)) -(defvar *sm-fast-function-index* - (!bootstrap-slot-index 'standard-method 'fast-function)) (defvar *sm-%function-index* (!bootstrap-slot-index 'standard-method '%function)) +(defvar *sm-qualifiers-index* + (!bootstrap-slot-index 'standard-method 'qualifiers)) (defvar *sm-plist-index* (!bootstrap-slot-index 'standard-method 'plist)) @@ -1765,7 +1759,7 @@ bootstrapping. ;;; class and deal with it as appropriate. In fact we probably don't ;;; need it anyway because we only use this for METHOD-SPECIALIZERS on ;;; the standard reader method for METHOD-SPECIALIZERS. Probably. -(dolist (s '(specializers fast-function %function plist)) +(dolist (s '(specializers %function plist)) (aver (= (symbol-value (intern (format nil "*SM-~A-INDEX*" s))) (!bootstrap-slot-index 'standard-reader-method s) (!bootstrap-slot-index 'standard-writer-method s) @@ -1782,15 +1776,9 @@ bootstrapping. (clos-slots-ref (get-slots method) *sm-specializers-index*) (method-specializers method)))) (defun safe-method-fast-function (method) - (let ((standard-method-classes - (list *the-class-standard-method* - *the-class-standard-reader-method* - *the-class-standard-writer-method* - *the-class-standard-boundp-method*)) - (class (class-of method))) - (if (member class standard-method-classes) - (clos-slots-ref (get-slots method) *sm-fast-function-index*) - (method-fast-function method)))) + (let ((mf (safe-method-function method))) + (and (typep mf '%method-function) + (%method-function-fast-function mf)))) (defun safe-method-function (method) (let ((standard-method-classes (list *the-class-standard-method* @@ -1809,8 +1797,7 @@ bootstrapping. *the-class-standard-boundp-method*)) (class (class-of method))) (if (member class standard-method-classes) - (let ((plist (clos-slots-ref (get-slots method) *sm-plist-index*))) - (getf plist 'qualifiers)) + (clos-slots-ref (get-slots method) *sm-qualifiers-index*) (method-qualifiers method)))) (defun set-arg-info1 (gf arg-info new-method methods was-valid-p first-p) @@ -1831,16 +1818,20 @@ bootstrapping. (class (if (or (eq *boot-state* 'complete) (not (consp method))) (class-of method) (early-method-class method))) - (new-type (when (and class - (or (not (eq *boot-state* 'complete)) - (eq (generic-function-method-combination gf) - *standard-method-combination*))) - (cond ((eq class *the-class-standard-reader-method*) - 'reader) - ((eq class *the-class-standard-writer-method*) - 'writer) - ((eq class *the-class-standard-boundp-method*) - 'boundp))))) + (new-type + (when (and class + (or (not (eq *boot-state* 'complete)) + (eq (generic-function-method-combination gf) + *standard-method-combination*))) + (cond ((or (eq class *the-class-standard-reader-method*) + (eq class *the-class-global-reader-method*)) + 'reader) + ((or (eq class *the-class-standard-writer-method*) + (eq class *the-class-global-writer-method*)) + 'writer) + ((or (eq class *the-class-standard-boundp-method*) + (eq class *the-class-global-boundp-method*)) + 'boundp))))) (setq metatypes (mapcar #'raise-metatype metatypes specializers)) (setq type (cond ((null type) new-type) ((eq type new-type) type) @@ -1928,7 +1919,8 @@ bootstrapping. (defun make-early-gf (spec &optional lambda-list lambda-list-p function argument-precedence-order source-location) - (let ((fin (allocate-funcallable-instance *sgf-wrapper* *sgf-slots-init*))) + (let ((fin (allocate-standard-funcallable-instance + *sgf-wrapper* *sgf-slots-init*))) (set-funcallable-instance-function fin (or function @@ -2031,6 +2023,12 @@ bootstrapping. (error "The :GENERIC-FUNCTION-CLASS argument (~S) was neither a~%~ class nor a symbol that names a class." ,gf-class))) + (unless (class-finalized-p ,gf-class) + (if (class-has-a-forward-referenced-superclass-p ,gf-class) + ;; FIXME: reference MOP documentation -- this is an + ;; additional requirement on our users + (error "The generic function class ~S is not finalizeable" ,gf-class) + (finalize-inheritance ,gf-class))) (remf ,all-keys :generic-function-class) (remf ,all-keys :environment) (let ((combin (getf ,all-keys :method-combination '.shes-not-there.))) @@ -2051,11 +2049,12 @@ bootstrapping. fun-name &rest all-keys &key environment (lambda-list nil lambda-list-p) - (generic-function-class 'standard-generic-function gf-class-p) + (generic-function-class 'standard-generic-function) &allow-other-keys) (real-ensure-gf-internal generic-function-class all-keys environment) - (unless (or (null gf-class-p) - (eq (class-of existing) generic-function-class)) + ;; KLUDGE: the above macro does SETQ on GENERIC-FUNCTION-CLASS, + ;; which is what makes the next line work + (unless (eq (class-of existing) generic-function-class) (change-class existing generic-function-class)) (prog1 (apply #'reinitialize-instance existing all-keys) @@ -2111,8 +2110,7 @@ bootstrapping. arg-info))) (defun early-make-a-method (class qualifiers arglist specializers initargs doc - &optional slot-name) - (initialize-method-function initargs) + &key slot-name object-class method-class-function) (let ((parsed ()) (unparsed ())) ;; Figure out whether we got class objects or class names as the @@ -2130,37 +2128,56 @@ bootstrapping. specializers)) (setq unparsed specializers parsed ())) - (list :early-method ;This is an early method dammit! - - (getf initargs :function) - (getf initargs :fast-function) - - parsed ;The parsed specializers. This is used - ;by early-method-specializers to cache - ;the parse. Note that this only comes - ;into play when there is more than one - ;early method on an early gf. - - (list class ;A list to which real-make-a-method - qualifiers ;can be applied to make a real method - arglist ;corresponding to this early one. - unparsed - initargs - doc - slot-name)))) + (let ((result + (list :early-method + + (getf initargs :function) + (let ((mf (getf initargs :function))) + (aver mf) + (and (typep mf '%method-function) + (%method-function-fast-function mf))) + + ;; the parsed specializers. This is used by + ;; EARLY-METHOD-SPECIALIZERS to cache the parse. + ;; Note that this only comes into play when there is + ;; more than one early method on an early gf. + parsed + + ;; A list to which REAL-MAKE-A-METHOD can be applied + ;; to make a real method corresponding to this early + ;; one. + (append + (list class qualifiers arglist unparsed + initargs doc) + (when slot-name + (list :slot-name slot-name :object-class object-class + :method-class-function method-class-function)))))) + (initialize-method-function initargs result) + result))) (defun real-make-a-method (class qualifiers lambda-list specializers initargs doc - &optional slot-name) + &rest args &key slot-name object-class method-class-function) (setq specializers (parse-specializers specializers)) - (apply #'make-instance class - :qualifiers qualifiers - :lambda-list lambda-list - :specializers specializers - :documentation doc - :slot-name slot-name - :allow-other-keys t - initargs)) + (if method-class-function + (let* ((object-class (if (classp object-class) object-class + (find-class object-class))) + (slots (class-direct-slots object-class)) + (slot-definition (find slot-name slots + :key #'slot-definition-name))) + (aver slot-name) + (aver slot-definition) + (let ((initargs (list* :qualifiers qualifiers :lambda-list lambda-list + :specializers specializers :documentation doc + :slot-definition slot-definition + :slot-name slot-name initargs))) + (apply #'make-instance + (apply method-class-function object-class slot-definition + initargs) + initargs))) + (apply #'make-instance class :qualifiers qualifiers + :lambda-list lambda-list :specializers specializers + :documentation doc (append args initargs)))) (defun early-method-function (early-method) (values (cadr early-method) (caddr early-method))) @@ -2175,7 +2192,7 @@ bootstrapping. (eq class 'standard-boundp-method)))) (defun early-method-standard-accessor-slot-name (early-method) - (seventh (fifth early-method))) + (eighth (fifth early-method))) ;;; Fetch the specializers of an early method. This is basically just ;;; a simple accessor except that when the second argument is t, this @@ -2199,21 +2216,31 @@ bootstrapping. (setf (fourth early-method) (mapcar #'find-class (cadddr (fifth early-method)))))) (t - (cadddr (fifth early-method)))) + (fourth (fifth early-method)))) (error "~S is not an early-method." early-method))) (defun early-method-qualifiers (early-method) - (cadr (fifth early-method))) + (second (fifth early-method))) (defun early-method-lambda-list (early-method) - (caddr (fifth early-method))) + (third (fifth early-method))) + +(defun early-method-initargs (early-method) + (fifth (fifth early-method))) + +(defun (setf early-method-initargs) (new-value early-method) + (setf (fifth (fifth early-method)) new-value)) (defun early-add-named-method (generic-function-name qualifiers specializers arglist &rest initargs) - (let* ((gf (ensure-generic-function generic-function-name)) + (let* (;; we don't need to deal with the :generic-function-class + ;; argument here because the default, + ;; STANDARD-GENERIC-FUNCTION, is right for all early generic + ;; functions. (See REAL-ADD-NAMED-METHOD) + (gf (ensure-generic-function generic-function-name)) (existing (dolist (m (early-gf-methods gf)) (when (and (equal (early-method-specializers m) specializers)