(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)