Initial revision
[sbcl.git] / src / pcl / dfun.lisp
1 ;;;; This software is part of the SBCL system. See the README file for
2 ;;;; more information.
3
4 ;;;; This software is derived from software originally released by Xerox
5 ;;;; Corporation. Copyright and release statements follow. Later modifications
6 ;;;; to the software are in the public domain and are provided with
7 ;;;; absolutely no warranty. See the COPYING and CREDITS files for more
8 ;;;; information.
9
10 ;;;; copyright information from original PCL sources:
11 ;;;;
12 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
13 ;;;; All rights reserved.
14 ;;;;
15 ;;;; Use and copying of this software and preparation of derivative works based
16 ;;;; upon this software are permitted. Any distribution of this software or
17 ;;;; derivative works must comply with all applicable United States export
18 ;;;; control laws.
19 ;;;;
20 ;;;; This software is made available AS IS, and Xerox Corporation makes no
21 ;;;; warranty about the software, its performance or its conformity to any
22 ;;;; specification.
23
24 (in-package "SB-PCL")
25
26 (sb-int:file-comment
27   "$Header$")
28 \f
29 #|
30
31 This implementation of method lookup was redone in early August of 89.
32
33 It has the following properties:
34
35  - Its modularity makes it easy to modify the actual caching algorithm.
36    The caching algorithm is almost completely separated into the files
37    cache.lisp and dlap.lisp. This file just contains the various uses
38    of it. There will be more tuning as we get more results from Luis'
39    measurements of caching behavior.
40
41  - The metacircularity issues have been dealt with properly. All of
42    PCL now grounds out properly. Moreover, it is now possible to have
43    metaobject classes which are themselves not instances of standard
44    metaobject classes.
45
46 ** Modularity of the code **
47
48 The actual caching algorithm is isolated in a modest number of functions.
49 The code which generates cache lookup code is all found in cache.lisp and
50 dlap.lisp. Certain non-wrapper-caching special cases are in this file.
51
52 ** Handling the metacircularity **
53
54 In CLOS, method lookup is the potential source of infinite metacircular
55 regress. The metaobject protocol specification gives us wide flexibility
56 in how to address this problem. PCL uses a technique which handles the
57 problem not only for the metacircular language described in Chapter 3, but
58 also for the PCL protocol which includes additional generic functions
59 which control more aspects of the CLOS implementation.
60
61 The source of the metacircular regress can be seen in a number of ways.
62 One is that the specified method lookup protocol must, as part of doing
63 the method lookup (or at least the cache miss case), itself call generic
64 functions. It is easy to see that if the method lookup for a generic
65 function ends up calling that same generic function there can be trouble.
66
67 Fortunately, there is an easy solution at hand. The solution is based on
68 the restriction that portable code cannot change the class of a specified
69 metaobject. This restriction implies that for specified generic functions,
70 the method lookup protocol they follow is fixed.
71
72 More precisely, for such specified generic functions, most generic functions
73 that are called during their own method lookup will not run portable methods.
74 This allows the implementation to usurp the actual generic function call in
75 this case. In short, method lookup of a standard generic function, in the
76 case where the only applicable methods are themselves standard doesn't
77 have to do any method lookup to implement itself.
78
79 And so, we are saved.
80
81 |#
82 \f
83 ;;; an alist in which each entry is of the form
84 ;;;   (<generator> . (<subentry> ...)).
85 ;;; Each subentry is of the form
86 ;;;   (<args> <constructor> <system>).
87 (defvar *dfun-constructors* ())                 
88
89 ;;; If this is NIL, then the whole mechanism for caching dfun constructors is
90 ;;; turned off. The only time that makes sense is when debugging LAP code.
91 (defvar *enable-dfun-constructor-caching* t)    
92
93 (defun show-dfun-constructors ()
94   (format t "~&DFUN constructor caching is ~A."
95           (if *enable-dfun-constructor-caching*
96               "enabled" "disabled"))
97   (dolist (generator-entry *dfun-constructors*)
98     (dolist (args-entry (cdr generator-entry))
99       (format t "~&~S ~S"
100               (cons (car generator-entry) (caar args-entry))
101               (caddr args-entry)))))
102
103 (defvar *raise-metatypes-to-class-p* t)
104
105 (defun get-dfun-constructor (generator &rest args)
106   (when (and *raise-metatypes-to-class-p*
107              (member generator '(emit-checking emit-caching
108                                  emit-in-checking-cache-p emit-constant-value)))
109     (setq args (cons (mapcar #'(lambda (mt)
110                                  (if (eq mt 't)
111                                      mt
112                                      'class))
113                              (car args))
114                      (cdr args))))
115   (let* ((generator-entry (assq generator *dfun-constructors*))
116          (args-entry (assoc args (cdr generator-entry) :test #'equal)))
117     (if (null *enable-dfun-constructor-caching*)
118         (apply (symbol-function generator) args)
119         (or (cadr args-entry)
120             (multiple-value-bind (new not-best-p)
121                 (apply (symbol-function generator) args)
122               (let ((entry (list (copy-list args) new (unless not-best-p 'pcl)
123                                  not-best-p)))
124                 (if generator-entry
125                     (push entry (cdr generator-entry))
126                     (push (list generator entry)
127                           *dfun-constructors*)))
128               (values new not-best-p))))))
129
130 (defun load-precompiled-dfun-constructor (generator args system constructor)
131   (let* ((generator-entry (assq generator *dfun-constructors*))
132          (args-entry (assoc args (cdr generator-entry) :test #'equal)))
133     (if args-entry
134         (when (fourth args-entry)
135           (let* ((dfun-type (case generator
136                               (emit-checking 'checking)
137                               (emit-caching 'caching)
138                               (emit-constant-value 'constant-value)
139                               (emit-default-only 'default-method-only)))
140                  (metatypes (car args))
141                  (gfs (when dfun-type (gfs-of-type dfun-type))))
142             (dolist (gf gfs)
143               (when (and (equal metatypes (arg-info-metatypes (gf-arg-info gf)))
144                          (let ((gf-name (generic-function-name gf)))
145                            (and (not (eq gf-name 'slot-value-using-class))
146                                 (not (equal gf-name '(setf slot-value-using-class)))
147                                 (not (eq gf-name 'slot-boundp-using-class)))))
148                 (update-dfun gf)))
149             (setf (second args-entry) constructor)
150             (setf (third args-entry) system)
151             (setf (fourth args-entry) nil)))
152         (let ((entry (list args constructor system nil)))
153           (if generator-entry
154               (push entry (cdr generator-entry))
155               (push (list generator entry) *dfun-constructors*))))))
156
157 (defmacro precompile-dfun-constructors (&optional system)
158   (let ((*precompiling-lap* t))
159     `(progn
160        ,@(gathering1 (collecting)
161            (dolist (generator-entry *dfun-constructors*)
162              (dolist (args-entry (cdr generator-entry))
163                (when (or (null (caddr args-entry))
164                          (eq (caddr args-entry) system))
165                  (when system (setf (caddr args-entry) system))
166                  (gather1
167                    (make-top-level-form `(precompile-dfun-constructor
168                                           ,(car generator-entry))
169                                         '(:load-toplevel)
170                      `(load-precompiled-dfun-constructor
171                        ',(car generator-entry)
172                        ',(car args-entry)
173                        ',system
174                        ,(apply (symbol-function (car generator-entry))
175                                (car args-entry))))))))))))
176 \f
177 ;;; When all the methods of a generic function are automatically generated
178 ;;; reader or writer methods a number of special optimizations are possible.
179 ;;; These are important because of the large number of generic functions of
180 ;;; this type.
181 ;;;
182 ;;; There are a number of cases:
183 ;;;
184 ;;;   ONE-CLASS-ACCESSOR
185 ;;;     In this case, the accessor generic function has only been called
186 ;;;     with one class of argument. There is no cache vector, the wrapper
187 ;;;     of the one class, and the slot index are stored directly as closure
188 ;;;     variables of the discriminating function. This case can convert to
189 ;;;     either of the next kind.
190 ;;;
191 ;;;   TWO-CLASS-ACCESSOR
192 ;;;     Like above, but two classes. This is common enough to do specially.
193 ;;;     There is no cache vector. The two classes are stored a separate
194 ;;;     closure variables.
195 ;;;
196 ;;;   ONE-INDEX-ACCESSOR
197 ;;;     In this case, the accessor generic function has seen more than one
198 ;;;     class of argument, but the index of the slot is the same for all
199 ;;;     the classes that have been seen. A cache vector is used to store
200 ;;;     the wrappers that have been seen, the slot index is stored directly
201 ;;;     as a closure variable of the discriminating function. This case
202 ;;;     can convert to the next kind.
203 ;;;
204 ;;;   N-N-ACCESSOR
205 ;;;     This is the most general case. In this case, the accessor generic
206 ;;;     function has seen more than one class of argument and more than one
207 ;;;     slot index. A cache vector stores the wrappers and corresponding
208 ;;;     slot indexes. Because each cache line is more than one element
209 ;;;     long, a cache lock count is used.
210 (defstruct (dfun-info (:constructor nil))
211   (cache nil))
212
213 (defstruct (no-methods
214              (:constructor no-methods-dfun-info ())
215              (:include dfun-info)))
216
217 (defstruct (initial
218              (:constructor initial-dfun-info ())
219              (:include dfun-info)))
220
221 (defstruct (initial-dispatch
222              (:constructor initial-dispatch-dfun-info ())
223              (:include dfun-info)))
224
225 (defstruct (dispatch
226              (:constructor dispatch-dfun-info ())
227              (:include dfun-info)))
228
229 (defstruct (default-method-only
230              (:constructor default-method-only-dfun-info ())
231              (:include dfun-info)))
232
233 ;without caching:
234 ;  dispatch one-class two-class default-method-only
235
236 ;with caching:
237 ;  one-index n-n checking caching
238
239 ;accessor:
240 ;  one-class two-class one-index n-n
241 (defstruct (accessor-dfun-info
242              (:constructor nil)
243              (:include dfun-info))
244   accessor-type) ; (member reader writer)
245
246 (defmacro dfun-info-accessor-type (di)
247   `(accessor-dfun-info-accessor-type ,di))
248
249 (defstruct (one-index-dfun-info
250              (:constructor nil)
251              (:include accessor-dfun-info))
252   index)
253
254 (defmacro dfun-info-index (di)
255   `(one-index-dfun-info-index ,di))
256
257 (defstruct (n-n
258              (:constructor n-n-dfun-info (accessor-type cache))
259              (:include accessor-dfun-info)))
260
261 (defstruct (one-class
262              (:constructor one-class-dfun-info (accessor-type index wrapper0))
263              (:include one-index-dfun-info))
264   wrapper0)
265
266 (defmacro dfun-info-wrapper0 (di)
267   `(one-class-wrapper0 ,di))
268
269 (defstruct (two-class
270              (:constructor two-class-dfun-info (accessor-type index wrapper0 wrapper1))
271              (:include one-class))
272   wrapper1)
273
274 (defmacro dfun-info-wrapper1 (di)
275   `(two-class-wrapper1 ,di))
276
277 (defstruct (one-index
278              (:constructor one-index-dfun-info
279                            (accessor-type index cache))
280              (:include one-index-dfun-info)))
281
282 (defstruct (checking
283              (:constructor checking-dfun-info (function cache))
284              (:include dfun-info))
285   function)
286
287 (defmacro dfun-info-function (di)
288   `(checking-function ,di))
289
290 (defstruct (caching
291              (:constructor caching-dfun-info (cache))
292              (:include dfun-info)))
293
294 (defstruct (constant-value
295              (:constructor constant-value-dfun-info (cache))
296              (:include dfun-info)))
297
298 (defmacro dfun-update (generic-function function &rest args)
299   `(multiple-value-bind (dfun cache info)
300        (funcall ,function ,generic-function ,@args)
301      (update-dfun ,generic-function dfun cache info)))
302
303 (defun accessor-miss-function (gf dfun-info)
304   (ecase (dfun-info-accessor-type dfun-info)
305     (reader
306       #'(lambda (arg)
307            (declare (pcl-fast-call))
308            (accessor-miss gf nil arg dfun-info)))
309     (writer
310      #'(lambda (new arg)
311          (declare (pcl-fast-call))
312          (accessor-miss gf new arg dfun-info)))))
313
314 #-sb-fluid (declaim (sb-ext:freeze-type dfun-info))
315 \f
316 (defun make-one-class-accessor-dfun (gf type wrapper index)
317   (let ((emit (if (eq type 'reader) 'emit-one-class-reader 'emit-one-class-writer))
318         (dfun-info (one-class-dfun-info type index wrapper)))
319     (values
320      (funcall (get-dfun-constructor emit (consp index))
321               wrapper index
322               (accessor-miss-function gf dfun-info))
323      nil
324      dfun-info)))
325
326 (defun make-two-class-accessor-dfun (gf type w0 w1 index)
327   (let ((emit (if (eq type 'reader) 'emit-two-class-reader 'emit-two-class-writer))
328         (dfun-info (two-class-dfun-info type index w0 w1)))
329     (values
330      (funcall (get-dfun-constructor emit (consp index))
331               w0 w1 index
332               (accessor-miss-function gf dfun-info))
333      nil
334      dfun-info)))
335
336 ;;; std accessors same index dfun
337 (defun make-one-index-accessor-dfun (gf type index &optional cache)
338   (let* ((emit (if (eq type 'reader) 'emit-one-index-readers 'emit-one-index-writers))
339          (cache (or cache (get-cache 1 nil #'one-index-limit-fn 4)))
340          (dfun-info (one-index-dfun-info type index cache)))
341     (declare (type cache cache))
342     (values
343      (funcall (get-dfun-constructor emit (consp index))
344               cache
345               index
346               (accessor-miss-function gf dfun-info))
347      cache
348      dfun-info)))
349
350 (defun make-final-one-index-accessor-dfun (gf type index table)
351   (let ((cache (fill-dfun-cache table nil 1 #'one-index-limit-fn)))
352     (make-one-index-accessor-dfun gf type index cache)))
353
354 (defun one-index-limit-fn (nlines)
355   (default-limit-fn nlines))
356
357 (defun make-n-n-accessor-dfun (gf type &optional cache)
358   (let* ((emit (if (eq type 'reader) 'emit-n-n-readers 'emit-n-n-writers))
359          (cache (or cache (get-cache 1 t #'n-n-accessors-limit-fn 2)))
360          (dfun-info (n-n-dfun-info type cache)))
361     (declare (type cache cache))
362     (values
363      (funcall (get-dfun-constructor emit)
364               cache
365               (accessor-miss-function gf dfun-info))
366      cache
367      dfun-info)))
368
369 (defun make-final-n-n-accessor-dfun (gf type table)
370   (let ((cache (fill-dfun-cache table t 1 #'n-n-accessors-limit-fn)))
371     (make-n-n-accessor-dfun gf type cache)))
372
373 (defun n-n-accessors-limit-fn (nlines)
374   (default-limit-fn nlines))
375
376 (defun make-checking-dfun (generic-function function &optional cache)
377   (unless cache
378     (when (use-caching-dfun-p generic-function)
379       (return-from make-checking-dfun (make-caching-dfun generic-function)))
380     (when (use-dispatch-dfun-p generic-function)
381       (return-from make-checking-dfun (make-dispatch-dfun generic-function))))
382   (multiple-value-bind (nreq applyp metatypes nkeys)
383       (get-generic-function-info generic-function)
384     (declare (ignore nreq))
385     (if (every #'(lambda (mt) (eq mt 't)) metatypes)
386         (let ((dfun-info (default-method-only-dfun-info)))
387           (values
388            (funcall (get-dfun-constructor 'emit-default-only metatypes applyp)
389                     function)
390            nil
391            dfun-info))
392         (let* ((cache (or cache (get-cache nkeys nil #'checking-limit-fn 2)))
393                (dfun-info (checking-dfun-info function cache)))
394           (values
395            (funcall (get-dfun-constructor 'emit-checking metatypes applyp)
396                     cache
397                     function
398                     #'(lambda (&rest args)
399                         (declare (pcl-fast-call))
400                         (checking-miss generic-function args dfun-info)))
401            cache
402            dfun-info)))))
403
404 (defun make-final-checking-dfun (generic-function function
405                                                   classes-list new-class)
406   (let ((metatypes (arg-info-metatypes (gf-arg-info generic-function))))
407     (if (every #'(lambda (mt) (eq mt 't)) metatypes)
408         (values #'(lambda (&rest args)
409                     (invoke-emf function args))
410                 nil (default-method-only-dfun-info))
411         (let ((cache (make-final-ordinary-dfun-internal
412                       generic-function nil #'checking-limit-fn
413                       classes-list new-class)))
414           (make-checking-dfun generic-function function cache)))))
415
416 (defun use-default-method-only-dfun-p (generic-function)
417   (multiple-value-bind (nreq applyp metatypes nkeys)
418       (get-generic-function-info generic-function)
419     (declare (ignore nreq applyp nkeys))
420     (every #'(lambda (mt) (eq mt 't)) metatypes)))
421
422 (defun use-caching-dfun-p (generic-function)
423   (some (lambda (method)
424           (let ((fmf (if (listp method)
425                          (third method)
426                          (method-fast-function method))))
427             (method-function-get fmf ':slot-name-lists)))
428         ;; KLUDGE: As of sbcl-0.6.4, it's very important for
429         ;; efficiency to know the type of the sequence argument to
430         ;; quantifiers (SOME/NOTANY/etc.) at compile time, but
431         ;; the compiler isn't smart enough to understand the :TYPE
432         ;; slot option for DEFCLASS, so we just tell
433         ;; it the type by hand here.
434         (the list 
435              (if (early-gf-p generic-function)
436                  (early-gf-methods generic-function)
437                  (generic-function-methods generic-function)))))
438
439 (defun checking-limit-fn (nlines)
440   (default-limit-fn nlines))
441 \f
442 (defun make-caching-dfun (generic-function &optional cache)
443   (unless cache
444     (when (use-constant-value-dfun-p generic-function)
445       (return-from make-caching-dfun (make-constant-value-dfun generic-function)))
446     (when (use-dispatch-dfun-p generic-function)
447       (return-from make-caching-dfun (make-dispatch-dfun generic-function))))
448   (multiple-value-bind (nreq applyp metatypes nkeys)
449       (get-generic-function-info generic-function)
450     (declare (ignore nreq))
451     (let* ((cache (or cache (get-cache nkeys t #'caching-limit-fn 2)))
452            (dfun-info (caching-dfun-info cache)))
453       (values
454        (funcall (get-dfun-constructor 'emit-caching metatypes applyp)
455                 cache
456                 #'(lambda (&rest args)
457                     (declare (pcl-fast-call))
458                     (caching-miss generic-function args dfun-info)))
459        cache
460        dfun-info))))
461
462 (defun make-final-caching-dfun (generic-function classes-list new-class)
463   (let ((cache (make-final-ordinary-dfun-internal
464                 generic-function t #'caching-limit-fn
465                 classes-list new-class)))
466     (make-caching-dfun generic-function cache)))
467
468 (defun caching-limit-fn (nlines)
469   (default-limit-fn nlines))
470
471 (defun insure-caching-dfun (gf)
472   (multiple-value-bind (nreq applyp metatypes nkeys)
473       (get-generic-function-info gf)
474     (declare (ignore nreq nkeys))
475     (when (and metatypes
476                (not (null (car metatypes)))
477                (dolist (mt metatypes nil)
478                  (unless (eq mt 't) (return t))))
479       (get-dfun-constructor 'emit-caching metatypes applyp))))
480
481 (defun use-constant-value-dfun-p (gf &optional boolean-values-p)
482   (multiple-value-bind (nreq applyp metatypes nkeys)
483       (get-generic-function-info gf)
484     (declare (ignore nreq metatypes nkeys))
485     (let* ((early-p (early-gf-p gf))
486            (methods (if early-p
487                         (early-gf-methods gf)
488                         (generic-function-methods gf)))
489            (default '(unknown)))
490       (and (null applyp)
491            (or (not (eq *boot-state* 'complete))
492                (compute-applicable-methods-emf-std-p gf))
493            (notany #'(lambda (method)
494                        (or (and (eq *boot-state* 'complete)
495                                 (some #'eql-specializer-p
496                                       (method-specializers method)))
497                            (let ((value (method-function-get
498                                          (if early-p
499                                              (or (third method) (second method))
500                                              (or (method-fast-function method)
501                                                  (method-function method)))
502                                          :constant-value default)))
503                              (if boolean-values-p
504                                  (not (or (eq value 't) (eq value nil)))
505                                  (eq value default)))))
506                    methods)))))
507
508 (defun make-constant-value-dfun (generic-function &optional cache)
509   (multiple-value-bind (nreq applyp metatypes nkeys)
510       (get-generic-function-info generic-function)
511     (declare (ignore nreq applyp))
512     (let* ((cache (or cache (get-cache nkeys t #'caching-limit-fn 2)))
513            (dfun-info (constant-value-dfun-info cache)))
514       (values
515        (funcall (get-dfun-constructor 'emit-constant-value metatypes)
516                 cache
517                 #'(lambda (&rest args)
518                     (declare (pcl-fast-call))
519                     (constant-value-miss generic-function args dfun-info)))
520        cache
521        dfun-info))))
522
523 (defun make-final-constant-value-dfun (generic-function classes-list new-class)
524   (let ((cache (make-final-ordinary-dfun-internal
525                 generic-function :constant-value #'caching-limit-fn
526                 classes-list new-class)))
527     (make-constant-value-dfun generic-function cache)))
528
529 (defun use-dispatch-dfun-p (gf &optional (caching-p (use-caching-dfun-p gf)))
530   (when (eq *boot-state* 'complete)
531     (unless caching-p
532       ;; This should return T when almost all dispatching is by
533       ;; eql specializers or built-in classes. In other words,
534       ;; return NIL if we might ever need to do more than
535       ;; one (non built-in) typep.
536       ;; Otherwise, it is probably at least as fast to use
537       ;; a caching dfun first, possibly followed by secondary dispatching.
538
539       #||;;; Original found in cmu 17f -- S L O W
540       (< (dispatch-dfun-cost gf) (caching-dfun-cost gf))
541       ||#
542       ;; This uses improved dispatch-dfun-cost below
543       (let ((cdc  (caching-dfun-cost gf))) ; fast
544         (> cdc (dispatch-dfun-cost gf cdc))))))
545
546 (defparameter *non-built-in-typep-cost* 1)
547 (defparameter *structure-typep-cost* 1)
548 (defparameter *built-in-typep-cost* 0)
549
550 ;;; The execution time of this version is exponential to some function
551 ;;; of number of gf methods and argument lists. It was taking
552 ;;; literally hours to load the presentation methods from the
553 ;;; cl-http w3p kit.
554 #+nil
555 (defun dispatch-dfun-cost (gf)
556   (generate-discrimination-net-internal
557    gf (generic-function-methods gf) nil
558    #'(lambda (methods known-types)
559        (declare (ignore methods known-types))
560        0)
561    #'(lambda (position type true-value false-value)
562        (declare (ignore position))
563        (+ (max true-value false-value)
564           (if (eq 'class (car type))
565               (let ((cpl (class-precedence-list (class-of (cadr type)))))
566                 (cond((memq *the-class-built-in-class* cpl)
567                       *built-in-typep-cost*)
568                      ((memq *the-class-structure-class* cpl)
569                       *structure-typep-cost*)
570                      (t
571                       *non-built-in-typep-cost*)))
572               0)))
573    #'identity))
574
575 ;;; This version is from the pcl found in the gcl-2.1 distribution.
576 ;;; Someone added a cost limit so as to keep the execution time controlled
577 (defun dispatch-dfun-cost (gf &optional limit)
578   (generate-discrimination-net-internal
579    gf (generic-function-methods gf) nil
580    #'(lambda (methods known-types)
581        (declare (ignore methods known-types))
582        0)
583    #'(lambda (position type true-value false-value)
584        (declare (ignore position))
585        (let* ((type-test-cost
586                (if (eq 'class (car type))
587                    (let* ((metaclass (class-of (cadr type)))
588                           (mcpl (class-precedence-list metaclass)))
589                      (cond ((memq *the-class-built-in-class* mcpl)
590                             *built-in-typep-cost*)
591                            ((memq *the-class-structure-class* mcpl)
592                             *structure-typep-cost*)
593                            (t
594                             *non-built-in-typep-cost*)))
595                    0))
596               (max-cost-so-far
597                (+ (max true-value false-value) type-test-cost)))
598          (when (and limit (<= limit max-cost-so-far))
599            (return-from dispatch-dfun-cost max-cost-so-far))
600            max-cost-so-far))
601    #'identity))
602
603 (defparameter *cache-lookup-cost* 1)
604 (defparameter *wrapper-of-cost* 0)
605 (defparameter *secondary-dfun-call-cost* 1)
606
607 (defun caching-dfun-cost (gf)
608   (let* ((arg-info (gf-arg-info gf))
609          (nreq (length (arg-info-metatypes arg-info))))
610     (+ *cache-lookup-cost*
611        (* *wrapper-of-cost* nreq)
612        (if (methods-contain-eql-specializer-p
613             (generic-function-methods gf))
614            *secondary-dfun-call-cost*
615            0))))
616
617 (setq *non-built-in-typep-cost* 100)
618 (setq *structure-typep-cost* 15)
619 (setq *built-in-typep-cost* 5)
620 (setq *cache-lookup-cost* 30)
621 (setq *wrapper-of-cost* 15)
622 (setq *secondary-dfun-call-cost* 30)
623
624 (defun make-dispatch-dfun (gf)
625   (values (get-dispatch-function gf) nil (dispatch-dfun-info)))
626
627 (defun get-dispatch-function (gf)
628   (let ((methods (generic-function-methods gf)))
629     (function-funcall (get-secondary-dispatch-function1 gf methods nil nil nil
630                                                         nil nil t)
631                       nil nil)))
632
633 (defun make-final-dispatch-dfun (gf)
634   (make-dispatch-dfun gf))
635
636 (defun update-dispatch-dfuns ()
637   (dolist (gf (gfs-of-type '(dispatch initial-dispatch)))
638     (dfun-update gf #'make-dispatch-dfun)))
639
640 (defun fill-dfun-cache (table valuep nkeys limit-fn &optional cache)
641   (let ((cache (or cache (get-cache nkeys valuep limit-fn
642                                     (+ (hash-table-count table) 3)))))
643     (maphash #'(lambda (classes value)
644                  (setq cache (fill-cache cache
645                                          (class-wrapper classes)
646                                          value
647                                          t)))
648              table)
649     cache))
650
651 (defun make-final-ordinary-dfun-internal (generic-function valuep limit-fn
652                                                            classes-list new-class)
653   (let* ((arg-info (gf-arg-info generic-function))
654          (nkeys (arg-info-nkeys arg-info))
655          (new-class (and new-class
656                          (equal (type-of (gf-dfun-info generic-function))
657                                 (cond ((eq valuep t) 'caching)
658                                       ((eq valuep :constant-value) 'constant-value)
659                                       ((null valuep) 'checking)))
660                          new-class))
661          (cache (if new-class
662                     (copy-cache (gf-dfun-cache generic-function))
663                     (get-cache nkeys (not (null valuep)) limit-fn 4))))
664       (make-emf-cache generic-function valuep cache classes-list new-class)))
665 \f
666 (defvar *dfun-miss-gfs-on-stack* ())
667
668 (defmacro dfun-miss ((gf args wrappers invalidp nemf
669                       &optional type index caching-p applicable)
670                      &body body)
671   (unless applicable (setq applicable (gensym)))
672   `(multiple-value-bind (,nemf ,applicable ,wrappers ,invalidp
673                          ,@(when type `(,type ,index)))
674        (cache-miss-values ,gf ,args ',(cond (caching-p 'caching)
675                                             (type 'accessor)
676                                             (t 'checking)))
677      (when (and ,applicable (not (memq ,gf *dfun-miss-gfs-on-stack*)))
678        (let ((*dfun-miss-gfs-on-stack* (cons ,gf *dfun-miss-gfs-on-stack*)))
679          ,@body))
680      (invoke-emf ,nemf ,args)))
681
682 ;;; The dynamically adaptive method lookup algorithm is implemented is
683 ;;; implemented as a kind of state machine. The kinds of discriminating
684 ;;; function is the state, the various kinds of reasons for a cache miss
685 ;;; are the state transitions.
686 ;;;
687 ;;; The code which implements the transitions is all in the miss handlers
688 ;;; for each kind of dfun. Those appear here.
689 ;;;
690 ;;; Note that within the states that cache, there are dfun updates which
691 ;;; simply select a new cache or cache field. Those are not considered
692 ;;; as state transitions.
693 (defvar *lazy-dfun-compute-p* t)
694 (defvar *early-p* nil)
695
696 (defun make-initial-dfun (gf)
697   (let ((initial-dfun
698          #'(sb-kernel:instance-lambda (&rest args)
699              (initial-dfun gf args))))
700     (multiple-value-bind (dfun cache info)
701         (if (and (eq *boot-state* 'complete)
702                  (compute-applicable-methods-emf-std-p gf))
703             (let* ((caching-p (use-caching-dfun-p gf))
704                    (classes-list (precompute-effective-methods
705                                   gf caching-p
706                                   (not *lazy-dfun-compute-p*))))
707               (if *lazy-dfun-compute-p*
708                   (cond ((use-dispatch-dfun-p gf caching-p)
709                          (values initial-dfun
710                                  nil
711                                  (initial-dispatch-dfun-info)))
712                         (caching-p
713                          (insure-caching-dfun gf)
714                          (values initial-dfun nil (initial-dfun-info)))
715                         (t
716                          (values initial-dfun nil (initial-dfun-info))))
717                   (make-final-dfun-internal gf classes-list)))
718             (let ((arg-info (if (early-gf-p gf)
719                                 (early-gf-arg-info gf)
720                                 (gf-arg-info gf)))
721                   (type nil))
722               (if (and (gf-precompute-dfun-and-emf-p arg-info)
723                        (setq type (final-accessor-dfun-type gf)))
724                   (if *early-p*
725                       (values (make-early-accessor gf type) nil nil)
726                       (make-final-accessor-dfun gf type))
727                   (values initial-dfun nil (initial-dfun-info)))))
728       (set-dfun gf dfun cache info))))
729
730 (defun make-early-accessor (gf type)
731   (let* ((methods (early-gf-methods gf))
732          (slot-name (early-method-standard-accessor-slot-name (car methods))))
733     (ecase type
734       (reader #'(sb-kernel:instance-lambda (instance)
735                   (let* ((class (class-of instance))
736                          (class-name (bootstrap-get-slot 'class class 'name)))
737                     (bootstrap-get-slot class-name instance slot-name))))
738       (writer #'(sb-kernel:instance-lambda (new-value instance)
739                   (let* ((class (class-of instance))
740                          (class-name (bootstrap-get-slot 'class class 'name)))
741                     (bootstrap-set-slot class-name instance slot-name new-value)))))))
742
743 (defun initial-dfun (gf args)
744   (dfun-miss (gf args wrappers invalidp nemf ntype nindex)
745     (cond (invalidp)
746           ((and ntype nindex)
747            (dfun-update
748             gf #'make-one-class-accessor-dfun ntype wrappers nindex))
749           ((use-caching-dfun-p gf)
750            (dfun-update gf #'make-caching-dfun))
751           (t
752            (dfun-update
753             gf #'make-checking-dfun
754             ;; nemf is suitable only for caching, have to do this:
755             (cache-miss-values gf args 'checking))))))
756
757 (defun make-final-dfun (gf &optional classes-list)
758   (multiple-value-bind (dfun cache info)
759       (make-final-dfun-internal gf classes-list)
760     (set-dfun gf dfun cache info)))
761
762 (defvar *new-class* nil)
763
764 (defvar *free-hash-tables* (mapcar #'list '(eq equal eql)))
765
766 (defmacro with-hash-table ((table test) &body forms)
767   `(let* ((.free. (assoc ',test *free-hash-tables*))
768           (,table (if (cdr .free.)
769                       (pop (cdr .free.))
770                       (make-hash-table :test ',test))))
771      (multiple-value-prog1
772          (progn ,@forms)
773        (clrhash ,table)
774        (push ,table (cdr .free.)))))
775
776 (defmacro with-eq-hash-table ((table) &body forms)
777   `(with-hash-table (,table eq) ,@forms))
778
779 (defun final-accessor-dfun-type (gf)
780   (let ((methods (if (early-gf-p gf)
781                      (early-gf-methods gf)
782                      (generic-function-methods gf))))
783     (cond ((every #'(lambda (method)
784                       (if (consp method)
785                           (eq *the-class-standard-reader-method*
786                               (early-method-class method))
787                           (standard-reader-method-p method)))
788                   methods)
789            'reader)
790           ((every #'(lambda (method)
791                       (if (consp method)
792                           (eq *the-class-standard-writer-method*
793                               (early-method-class method))
794                           (standard-writer-method-p method)))
795                   methods)
796            'writer))))
797
798 (defun make-final-accessor-dfun (gf type &optional classes-list new-class)
799   (with-eq-hash-table (table)
800     (multiple-value-bind (table all-index first second size no-class-slots-p)
801         (make-accessor-table gf type table)
802       (if table
803           (cond ((= size 1)
804                  (let ((w (class-wrapper first)))
805                    (make-one-class-accessor-dfun gf type w all-index)))
806                 ((and (= size 2) (or (integerp all-index) (consp all-index)))
807                  (let ((w0 (class-wrapper first))
808                        (w1 (class-wrapper second)))
809                    (make-two-class-accessor-dfun gf type w0 w1 all-index)))
810                 ((or (integerp all-index) (consp all-index))
811                  (make-final-one-index-accessor-dfun
812                   gf type all-index table))
813                 (no-class-slots-p
814                  (make-final-n-n-accessor-dfun gf type table))
815                 (t
816                  (make-final-caching-dfun gf classes-list new-class)))
817           (make-final-caching-dfun gf classes-list new-class)))))
818
819 (defun make-final-dfun-internal (gf &optional classes-list)
820   (let ((methods (generic-function-methods gf)) type
821         (new-class *new-class*) (*new-class* nil)
822         specls all-same-p)
823     (cond ((null methods)
824            (values
825             #'(sb-kernel:instance-lambda (&rest args)
826                 (apply #'no-applicable-method gf args))
827             nil
828             (no-methods-dfun-info)))
829           ((setq type (final-accessor-dfun-type gf))
830            (make-final-accessor-dfun gf type classes-list new-class))
831           ((and (not (and (every #'(lambda (specl) (eq specl *the-class-t*))
832                                  (setq specls
833                                        (method-specializers (car methods))))
834                           (setq all-same-p
835                                 (every #'(lambda (method)
836                                            (and (equal specls
837                                                        (method-specializers
838                                                         method))))
839                                        methods))))
840                 (use-constant-value-dfun-p gf))
841            (make-final-constant-value-dfun gf classes-list new-class))
842           ((use-dispatch-dfun-p gf)
843            (make-final-dispatch-dfun gf))
844           ((and all-same-p (not (use-caching-dfun-p gf)))
845            (let ((emf (get-secondary-dispatch-function gf methods nil)))
846              (make-final-checking-dfun gf emf classes-list new-class)))
847           (t
848            (make-final-caching-dfun gf classes-list new-class)))))
849
850 (defun accessor-miss (gf new object dfun-info)
851   (let* ((ostate (type-of dfun-info))
852          (otype (dfun-info-accessor-type dfun-info))
853          oindex ow0 ow1 cache
854          (args (ecase otype                     ; The congruence rules ensure
855                 (reader (list object))          ; that this is safe despite not
856                 (writer (list new object)))))   ; knowing the new type yet.
857     (dfun-miss (gf args wrappers invalidp nemf ntype nindex)
858
859       ;; The following lexical functions change the state of the
860       ;; dfun to that which is their name. They accept arguments
861       ;; which are the parameters of the new state, and get other
862       ;; information from the lexical variables bound above.
863       (flet ((two-class (index w0 w1)
864                (when (zerop (random 2)) (psetf w0 w1 w1 w0))
865                (dfun-update gf
866                             #'make-two-class-accessor-dfun
867                             ntype
868                             w0
869                             w1
870                             index))
871              (one-index (index &optional cache)
872                (dfun-update gf
873                             #'make-one-index-accessor-dfun
874                             ntype
875                             index
876                             cache))
877              (n-n (&optional cache)
878                (if (consp nindex)
879                    (dfun-update gf #'make-checking-dfun nemf)
880                    (dfun-update gf #'make-n-n-accessor-dfun ntype cache)))
881              (caching () ; because cached accessor emfs are much faster
882                          ; for accessors
883                (dfun-update gf #'make-caching-dfun))
884              (do-fill (update-fn)
885                (let ((ncache (fill-cache cache wrappers nindex)))
886                  (unless (eq ncache cache)
887                    (funcall update-fn ncache)))))
888
889         (cond ((null ntype)
890                (caching))
891               ((or invalidp
892                    (null nindex)))
893               ((not (pcl-instance-p object))
894                (caching))
895               ((or (neq ntype otype) (listp wrappers))
896                (caching))
897               (t
898                (ecase ostate
899                  (one-class
900                   (setq oindex (dfun-info-index dfun-info))
901                   (setq ow0 (dfun-info-wrapper0 dfun-info))
902                   (unless (eq ow0 wrappers)
903                     (if (eql nindex oindex)
904                         (two-class nindex ow0 wrappers)
905                         (n-n))))
906                  (two-class
907                   (setq oindex (dfun-info-index dfun-info))
908                   (setq ow0 (dfun-info-wrapper0 dfun-info))
909                   (setq ow1 (dfun-info-wrapper1 dfun-info))
910                   (unless (or (eq ow0 wrappers) (eq ow1 wrappers))
911                     (if (eql nindex oindex)
912                         (one-index nindex)
913                         (n-n))))
914                  (one-index
915                   (setq oindex (dfun-info-index dfun-info))
916                   (setq cache (dfun-info-cache dfun-info))
917                   (if (eql nindex oindex)
918                       (do-fill #'(lambda (ncache)
919                                    (one-index nindex ncache)))
920                       (n-n)))
921                  (n-n
922                   (setq cache (dfun-info-cache dfun-info))
923                   (if (consp nindex)
924                       (caching)
925                       (do-fill #'n-n))))))))))
926
927 (defun checking-miss (generic-function args dfun-info)
928   (let ((oemf (dfun-info-function dfun-info))
929         (cache (dfun-info-cache dfun-info)))
930     (dfun-miss (generic-function args wrappers invalidp nemf)
931       (cond (invalidp)
932             ((eq oemf nemf)
933              (let ((ncache (fill-cache cache wrappers nil)))
934                (unless (eq ncache cache)
935                  (dfun-update generic-function #'make-checking-dfun
936                               nemf ncache))))
937             (t
938              (dfun-update generic-function #'make-caching-dfun))))))
939
940 (defun caching-miss (generic-function args dfun-info)
941   (let ((ocache (dfun-info-cache dfun-info)))
942     (dfun-miss (generic-function args wrappers invalidp emf nil nil t)
943       (cond (invalidp)
944             (t
945              (let ((ncache (fill-cache ocache wrappers emf)))
946                (unless (eq ncache ocache)
947                  (dfun-update generic-function
948                               #'make-caching-dfun ncache))))))))
949
950 (defun constant-value-miss (generic-function args dfun-info)
951   (let ((ocache (dfun-info-cache dfun-info)))
952     (dfun-miss (generic-function args wrappers invalidp emf nil nil t)
953       (cond (invalidp)
954             (t
955              (let* ((function (typecase emf
956                                 (fast-method-call (fast-method-call-function
957                                                    emf))
958                                 (method-call (method-call-function emf))))
959                     (value (method-function-get function :constant-value))
960                     (ncache (fill-cache ocache wrappers value)))
961                (unless (eq ncache ocache)
962                  (dfun-update generic-function
963                               #'make-constant-value-dfun ncache))))))))
964 \f
965 ;;; Given a generic function and a set of arguments to that generic function,
966 ;;; returns a mess of values.
967 ;;;
968 ;;;  <function>   The compiled effective method function for this set of
969 ;;;            arguments.
970 ;;;
971 ;;;  <applicable> Sorted list of applicable methods.
972 ;;;
973 ;;;  <wrappers>   Is a single wrapper if the generic function has only
974 ;;;            one key, that is arg-info-nkeys of the arg-info is 1.
975 ;;;            Otherwise a list of the wrappers of the specialized
976 ;;;            arguments to the generic function.
977 ;;;
978 ;;;            Note that all these wrappers are valid. This function
979 ;;;            does invalid wrapper traps when it finds an invalid
980 ;;;            wrapper and then returns the new, valid wrapper.
981 ;;;
982 ;;;  <invalidp>   True if any of the specialized arguments had an invalid
983 ;;;            wrapper, false otherwise.
984 ;;;
985 ;;;  <type>       READER or WRITER when the only method that would be run
986 ;;;            is a standard reader or writer method. To be specific,
987 ;;;            the value is READER when the method combination is eq to
988 ;;;            *standard-method-combination*; there are no applicable
989 ;;;            :before, :after or :around methods; and the most specific
990 ;;;            primary method is a standard reader method.
991 ;;;
992 ;;;  <index>      If <type> is READER or WRITER, and the slot accessed is
993 ;;;            an :instance slot, this is the index number of that slot
994 ;;;            in the object argument.
995 (defun cache-miss-values (gf args state)
996   (if (null (if (early-gf-p gf)
997                 (early-gf-methods gf)
998                 (generic-function-methods gf)))
999       (apply #'no-applicable-method gf args)
1000       (multiple-value-bind (nreq applyp metatypes nkeys arg-info)
1001           (get-generic-function-info gf)
1002         (declare (ignore nreq applyp nkeys))
1003         (with-dfun-wrappers (args metatypes)
1004           (dfun-wrappers invalid-wrapper-p wrappers classes types)
1005           (error "The function ~S requires at least ~D arguments"
1006                  gf (length metatypes))
1007           (multiple-value-bind (emf methods accessor-type index)
1008               (cache-miss-values-internal gf arg-info wrappers classes types state)
1009             (values emf methods
1010                     dfun-wrappers
1011                     invalid-wrapper-p
1012                     accessor-type index))))))
1013
1014 (defun cache-miss-values-internal (gf arg-info wrappers classes types state)
1015   (let* ((for-accessor-p (eq state 'accessor))
1016          (for-cache-p (or (eq state 'caching) (eq state 'accessor)))
1017          (cam-std-p (or (null arg-info)
1018                         (gf-info-c-a-m-emf-std-p arg-info))))
1019     (multiple-value-bind (methods all-applicable-and-sorted-p)
1020         (if cam-std-p
1021             (compute-applicable-methods-using-types gf types)
1022             (compute-applicable-methods-using-classes gf classes))
1023       (let ((emf (if (or cam-std-p all-applicable-and-sorted-p)
1024                      (function-funcall (get-secondary-dispatch-function1
1025                                         gf methods types nil (and for-cache-p wrappers)
1026                                         all-applicable-and-sorted-p)
1027                                        nil (and for-cache-p wrappers))
1028                      (default-secondary-dispatch-function gf))))
1029         (multiple-value-bind (index accessor-type)
1030             (and for-accessor-p all-applicable-and-sorted-p methods
1031                  (accessor-values gf arg-info classes methods))
1032           (values (if (integerp index) index emf)
1033                   methods accessor-type index))))))
1034
1035 (defun accessor-values (gf arg-info classes methods)
1036   (declare (ignore gf))
1037   (let* ((accessor-type (gf-info-simple-accessor-type arg-info))
1038          (accessor-class (case accessor-type
1039                            (reader (car classes))
1040                            (writer (cadr classes))
1041                            (boundp (car classes)))))
1042     (accessor-values-internal accessor-type accessor-class methods)))
1043
1044 (defun accessor-values1 (gf accessor-type accessor-class)
1045   (let* ((type `(class-eq ,accessor-class))
1046          (types (if (eq accessor-type 'writer) `(t ,type) `(,type)))
1047          (methods (compute-applicable-methods-using-types gf types)))
1048     (accessor-values-internal accessor-type accessor-class methods)))
1049
1050 (defun accessor-values-internal (accessor-type accessor-class methods)
1051   (dolist (meth methods)
1052     (when (if (consp meth)
1053               (early-method-qualifiers meth)
1054               (method-qualifiers meth))
1055       (return-from accessor-values-internal (values nil nil))))
1056   (let* ((meth (car methods))
1057          (early-p (not (eq *boot-state* 'complete)))
1058          (slot-name (when accessor-class
1059                       (if (consp meth)
1060                           (and (early-method-standard-accessor-p meth)
1061                                (early-method-standard-accessor-slot-name meth))
1062                           (and (member *the-class-std-object*
1063                                        (if early-p
1064                                            (early-class-precedence-list accessor-class)
1065                                            (class-precedence-list accessor-class)))
1066                                (if early-p
1067                                    (not (eq *the-class-standard-method*
1068                                             (early-method-class meth)))
1069                                    (standard-accessor-method-p meth))
1070                                (if early-p
1071                                    (early-accessor-method-slot-name meth)
1072                                    (accessor-method-slot-name meth))))))
1073          (slotd (and accessor-class
1074                      (if early-p
1075                          (dolist (slot (early-class-slotds accessor-class) nil)
1076                            (when (eql slot-name (early-slot-definition-name slot))
1077                              (return slot)))
1078                          (find-slot-definition accessor-class slot-name)))))
1079     (when (and slotd
1080                (or early-p
1081                    (slot-accessor-std-p slotd accessor-type)))
1082       (values (if early-p
1083                   (early-slot-definition-location slotd)
1084                   (slot-definition-location slotd))
1085               accessor-type))))
1086
1087 (defun make-accessor-table (gf type &optional table)
1088   (unless table (setq table (make-hash-table :test 'eq)))
1089   (let ((methods (if (early-gf-p gf)
1090                      (early-gf-methods gf)
1091                      (generic-function-methods gf)))
1092         (all-index nil)
1093         (no-class-slots-p t)
1094         (early-p (not (eq *boot-state* 'complete)))
1095         first second (size 0))
1096     (declare (fixnum size))
1097     ;; class -> {(specl slotd)}
1098     (dolist (method methods)
1099       (let* ((specializers (if (consp method)
1100                                (early-method-specializers method t)
1101                                (method-specializers method)))
1102              (specl (if (eq type 'reader)
1103                         (car specializers)
1104                         (cadr specializers)))
1105              (specl-cpl (if early-p
1106                             (early-class-precedence-list specl)
1107                             (and (class-finalized-p specl)
1108                                  (class-precedence-list specl))))
1109              (so-p (member *the-class-std-object* specl-cpl))
1110              (slot-name (if (consp method)
1111                             (and (early-method-standard-accessor-p method)
1112                                  (early-method-standard-accessor-slot-name method))
1113                             (accessor-method-slot-name method))))
1114         (when (or (null specl-cpl)
1115                   (member *the-class-structure-object* specl-cpl))
1116           (return-from make-accessor-table nil))
1117         (maphash #'(lambda (class slotd)
1118                      (let ((cpl (if early-p
1119                                     (early-class-precedence-list class)
1120                                     (class-precedence-list class))))
1121                        (when (memq specl cpl)
1122                          (unless (and (or so-p
1123                                           (member *the-class-std-object* cpl))
1124                                       (or early-p
1125                                           (slot-accessor-std-p slotd type)))
1126                            (return-from make-accessor-table nil))
1127                          (push (cons specl slotd) (gethash class table)))))
1128                  (gethash slot-name *name->class->slotd-table*))))
1129     (maphash #'(lambda (class specl+slotd-list)
1130                  (dolist (sclass (if early-p
1131                                     (early-class-precedence-list class)
1132                                     (class-precedence-list class))
1133                           (error "This can't happen"))
1134                    (let ((a (assq sclass specl+slotd-list)))
1135                      (when a
1136                        (let* ((slotd (cdr a))
1137                               (index (if early-p
1138                                          (early-slot-definition-location slotd)
1139                                          (slot-definition-location slotd))))
1140                          (unless index (return-from make-accessor-table nil))
1141                          (setf (gethash class table) index)
1142                          (when (consp index) (setq no-class-slots-p nil))
1143                          (setq all-index (if (or (null all-index)
1144                                                  (eql all-index index))
1145                                              index t))
1146                          (incf size)
1147                          (cond ((= size 1) (setq first class))
1148                                ((= size 2) (setq second class)))
1149                          (return nil))))))
1150              table)
1151     (values table all-index first second size no-class-slots-p)))
1152
1153 (defun compute-applicable-methods-using-types (generic-function types)
1154   (let ((definite-p t) (possibly-applicable-methods nil))
1155     (dolist (method (if (early-gf-p generic-function)
1156                         (early-gf-methods generic-function)
1157                         (generic-function-methods generic-function)))
1158       (let ((specls (if (consp method)
1159                         (early-method-specializers method t)
1160                         (method-specializers method)))
1161             (types types)
1162             (possibly-applicable-p t) (applicable-p t))
1163         (dolist (specl specls)
1164           (multiple-value-bind (specl-applicable-p specl-possibly-applicable-p)
1165               (specializer-applicable-using-type-p specl (pop types))
1166             (unless specl-applicable-p
1167               (setq applicable-p nil))
1168             (unless specl-possibly-applicable-p
1169               (setq possibly-applicable-p nil)
1170               (return nil))))
1171         (when possibly-applicable-p
1172           (unless applicable-p (setq definite-p nil))
1173           (push method possibly-applicable-methods))))
1174     (let ((precedence (arg-info-precedence (if (early-gf-p generic-function)
1175                                                (early-gf-arg-info generic-function)
1176                                                (gf-arg-info generic-function)))))
1177       (values (sort-applicable-methods precedence
1178                                        (nreverse possibly-applicable-methods)
1179                                        types)
1180               definite-p))))
1181
1182 (defun sort-applicable-methods (precedence methods types)
1183   (sort-methods methods
1184                 precedence
1185                 #'(lambda (class1 class2 index)
1186                     (let* ((class (type-class (nth index types)))
1187                            (cpl (if (eq *boot-state* 'complete)
1188                                     (class-precedence-list class)
1189                                     (early-class-precedence-list class))))
1190                       (if (memq class2 (memq class1 cpl))
1191                           class1 class2)))))
1192
1193 (defun sort-methods (methods precedence compare-classes-function)
1194   (flet ((sorter (method1 method2)
1195            (dolist (index precedence)
1196              (let* ((specl1 (nth index (if (listp method1)
1197                                            (early-method-specializers method1 t)
1198                                            (method-specializers method1))))
1199                     (specl2 (nth index (if (listp method2)
1200                                            (early-method-specializers method2 t)
1201                                            (method-specializers method2))))
1202                     (order (order-specializers
1203                              specl1 specl2 index compare-classes-function)))
1204                (when order
1205                  (return-from sorter (eq order specl1)))))))
1206     (stable-sort methods #'sorter)))
1207
1208 (defun order-specializers (specl1 specl2 index compare-classes-function)
1209   (let ((type1 (if (eq *boot-state* 'complete)
1210                    (specializer-type specl1)
1211                    (bootstrap-get-slot 'specializer specl1 'type)))
1212         (type2 (if (eq *boot-state* 'complete)
1213                    (specializer-type specl2)
1214                    (bootstrap-get-slot 'specializer specl2 'type))))
1215     (cond ((eq specl1 specl2)
1216            nil)
1217           ((atom type1)
1218            specl2)
1219           ((atom type2)
1220            specl1)
1221           (t
1222            (case (car type1)
1223              (class    (case (car type2)
1224                          (class (funcall compare-classes-function specl1 specl2 index))
1225                          (t specl2)))
1226              (prototype (case (car type2)
1227                          (class (funcall compare-classes-function specl1 specl2 index))
1228                          (t specl2)))
1229              (class-eq (case (car type2)
1230                          (eql specl2)
1231                          (class-eq nil)
1232                          (class type1)))
1233              (eql      (case (car type2)
1234                          (eql nil)
1235                          (t specl1))))))))
1236
1237 (defun map-all-orders (methods precedence function)
1238   (let ((choices nil))
1239     (flet ((compare-classes-function (class1 class2 index)
1240              (declare (ignore index))
1241              (let ((choice nil))
1242                (dolist (c choices nil)
1243                  (when (or (and (eq (first c) class1)
1244                                 (eq (second c) class2))
1245                            (and (eq (first c) class2)
1246                                 (eq (second c) class1)))
1247                    (return (setq choice c))))
1248                (unless choice
1249                  (setq choice
1250                        (if (class-might-precede-p class1 class2)
1251                            (if (class-might-precede-p class2 class1)
1252                                (list class1 class2 nil t)
1253                                (list class1 class2 t))
1254                            (if (class-might-precede-p class2 class1)
1255                                (list class2 class1 t)
1256                                (let ((name1 (class-name class1))
1257                                      (name2 (class-name class2)))
1258                                  (if (and name1 name2 (symbolp name1) (symbolp name2)
1259                                           (string< (symbol-name name1)
1260                                                    (symbol-name name2)))
1261                                      (list class1 class2 t)
1262                                      (list class2 class1 t))))))
1263                  (push choice choices))
1264                (car choice))))
1265       (loop (funcall function
1266                      (sort-methods methods precedence #'compare-classes-function))
1267             (unless (dolist (c choices nil)
1268                       (unless (third c)
1269                         (rotatef (car c) (cadr c))
1270                         (return (setf (third c) t))))
1271               (return nil))))))
1272
1273 (defvar *in-precompute-effective-methods-p* nil)
1274
1275 ;used only in map-all-orders
1276 (defun class-might-precede-p (class1 class2)
1277   (if (not *in-precompute-effective-methods-p*)
1278       (not (member class1 (cdr (class-precedence-list class2))))
1279       (class-can-precede-p class1 class2)))
1280
1281 (defun compute-precedence (lambda-list nreq argument-precedence-order)
1282   (if (null argument-precedence-order)
1283       (let ((list nil))
1284         (dotimes-fixnum (i nreq list) (push (- (1- nreq) i) list)))
1285       (mapcar (lambda (x) (position x lambda-list))
1286               argument-precedence-order)))
1287
1288 (defun saut-and (specl type)
1289   (let ((applicable nil)
1290         (possibly-applicable t))
1291     (dolist (type (cdr type))
1292       (multiple-value-bind (appl poss-appl)
1293           (specializer-applicable-using-type-p specl type)
1294         (when appl (return (setq applicable t)))
1295         (unless poss-appl (return (setq possibly-applicable nil)))))
1296     (values applicable possibly-applicable)))
1297
1298 (defun saut-not (specl type)
1299   (let ((ntype (cadr type)))
1300     (values nil
1301             (case (car ntype)
1302               (class      (saut-not-class specl ntype))
1303               (class-eq   (saut-not-class-eq specl ntype))
1304               (prototype  (saut-not-prototype specl ntype))
1305               (eql      (saut-not-eql specl ntype))
1306               (t (error "~S cannot handle the second argument ~S"
1307                         'specializer-applicable-using-type-p type))))))
1308
1309 (defun saut-not-class (specl ntype)
1310   (let* ((class (type-class specl))
1311          (cpl (class-precedence-list class)))
1312      (not (memq (cadr ntype) cpl))))
1313
1314 (defun saut-not-prototype (specl ntype)
1315   (let* ((class (case (car specl)
1316                   (eql       (class-of (cadr specl)))
1317                   (class-eq  (cadr specl))
1318                   (prototype (cadr specl))
1319                   (class     (cadr specl))))
1320          (cpl (class-precedence-list class)))
1321      (not (memq (cadr ntype) cpl))))
1322
1323 (defun saut-not-class-eq (specl ntype)
1324   (let ((class (case (car specl)
1325                  (eql      (class-of (cadr specl)))
1326                  (class-eq (cadr specl)))))
1327     (not (eq class (cadr ntype)))))
1328
1329 (defun saut-not-eql (specl ntype)
1330   (case (car specl)
1331     (eql (not (eql (cadr specl) (cadr ntype))))
1332     (t   t)))
1333
1334 (defun class-applicable-using-class-p (specl type)
1335   (let ((pred (memq specl (if (eq *boot-state* 'complete)
1336                               (class-precedence-list type)
1337                               (early-class-precedence-list type)))))
1338     (values pred
1339             (or pred
1340                 (if (not *in-precompute-effective-methods-p*)
1341                     ;; classes might get common subclass
1342                     (superclasses-compatible-p specl type)
1343                     ;; worry only about existing classes
1344                     (classes-have-common-subclass-p specl type))))))
1345
1346 (defun classes-have-common-subclass-p (class1 class2)
1347   (or (eq class1 class2)
1348       (let ((class1-subs (class-direct-subclasses class1)))
1349         (or (memq class2 class1-subs)
1350             (dolist (class1-sub class1-subs nil)
1351               (when (classes-have-common-subclass-p class1-sub class2)
1352                 (return t)))))))
1353
1354 (defun saut-class (specl type)
1355   (case (car specl)
1356     (class (class-applicable-using-class-p (cadr specl) (cadr type)))
1357     (t     (values nil (let ((class (type-class specl)))
1358                          (memq (cadr type)
1359                                (class-precedence-list class)))))))
1360
1361 (defun saut-class-eq (specl type)
1362   (if (eq (car specl) 'eql)
1363       (values nil (eq (class-of (cadr specl)) (cadr type)))
1364       (let ((pred (case (car specl)
1365                     (class-eq
1366                      (eq (cadr specl) (cadr type)))
1367                     (class
1368                      (or (eq (cadr specl) (cadr type))
1369                          (memq (cadr specl)
1370                                (if (eq *boot-state* 'complete)
1371                                    (class-precedence-list (cadr type))
1372                                    (early-class-precedence-list (cadr type)))))))))
1373         (values pred pred))))
1374
1375 (defun saut-prototype (specl type)
1376   (declare (ignore specl type))
1377   (values nil nil)) ; fix this someday
1378
1379 (defun saut-eql (specl type)
1380   (let ((pred (case (car specl)
1381                 (eql    (eql (cadr specl) (cadr type)))
1382                 (class-eq   (eq (cadr specl) (class-of (cadr type))))
1383                 (class      (memq (cadr specl)
1384                                   (let ((class (class-of (cadr type))))
1385                                     (if (eq *boot-state* 'complete)
1386                                         (class-precedence-list class)
1387                                         (early-class-precedence-list class))))))))
1388     (values pred pred)))
1389
1390 (defun specializer-applicable-using-type-p (specl type)
1391   (setq specl (type-from-specializer specl))
1392   (when (eq specl 't)
1393     (return-from specializer-applicable-using-type-p (values t t)))
1394   ;; This is used by c-a-m-u-t and generate-discrimination-net-internal,
1395   ;; and has only what they need.
1396   (if (or (atom type) (eq (car type) 't))
1397       (values nil t)
1398       (case (car type)
1399         (and    (saut-and specl type))
1400         (not    (saut-not specl type))
1401         (class      (saut-class specl type))
1402         (prototype  (saut-prototype specl type))
1403         (class-eq   (saut-class-eq specl type))
1404         (eql    (saut-eql specl type))
1405         (t        (error "~S cannot handle the second argument ~S."
1406                            'specializer-applicable-using-type-p
1407                            type)))))
1408
1409 (defun map-all-classes (function &optional (root 't))
1410   (let ((braid-p (or (eq *boot-state* 'braid)
1411                      (eq *boot-state* 'complete))))
1412     (labels ((do-class (class)
1413                (mapc #'do-class
1414                      (if braid-p
1415                          (class-direct-subclasses class)
1416                          (early-class-direct-subclasses class)))
1417                (funcall function class)))
1418       (do-class (if (symbolp root)
1419                     (find-class root)
1420                     root)))))
1421 \f
1422 ;;; NOTE: We are assuming a restriction on user code that the method
1423 ;;;       combination must not change once it is connected to the
1424 ;;;       generic function.
1425 ;;;
1426 ;;;       This has to be legal, because otherwise any kind of method
1427 ;;;       lookup caching couldn't work. See this by saying that this
1428 ;;;       cache, is just a backing cache for the fast cache. If that
1429 ;;;       cache is legal, this one must be too.
1430 ;;;
1431 ;;; Don't clear this table!
1432 (defvar *effective-method-table* (make-hash-table :test 'eq))
1433
1434 (defun get-secondary-dispatch-function (gf methods types &optional
1435                                                          method-alist wrappers)
1436   (function-funcall (get-secondary-dispatch-function1
1437                      gf methods types
1438                      (not (null method-alist))
1439                      (not (null wrappers))
1440                      (not (methods-contain-eql-specializer-p methods)))
1441                     method-alist wrappers))
1442
1443 (defun get-secondary-dispatch-function1 (gf methods types method-alist-p wrappers-p
1444                                             &optional all-applicable-p
1445                                             (all-sorted-p t) function-p)
1446   (if (null methods)
1447       (if function-p
1448           #'(lambda (method-alist wrappers)
1449               (declare (ignore method-alist wrappers))
1450               #'(sb-kernel:instance-lambda (&rest args)
1451                   (apply #'no-applicable-method gf args)))
1452           #'(lambda (method-alist wrappers)
1453               (declare (ignore method-alist wrappers))
1454               #'(lambda (&rest args)
1455                   (apply #'no-applicable-method gf args))))
1456       (let* ((key (car methods))
1457              (ht-value (or (gethash key *effective-method-table*)
1458                            (setf (gethash key *effective-method-table*)
1459                                  (cons nil nil)))))
1460         (if (and (null (cdr methods)) all-applicable-p ; the most common case
1461                  (null method-alist-p) wrappers-p (not function-p))
1462             (or (car ht-value)
1463                 (setf (car ht-value)
1464                       (get-secondary-dispatch-function2
1465                        gf methods types method-alist-p wrappers-p
1466                        all-applicable-p all-sorted-p function-p)))
1467             (let ((akey (list methods
1468                               (if all-applicable-p 'all-applicable types)
1469                               method-alist-p wrappers-p function-p)))
1470               (or (cdr (assoc akey (cdr ht-value) :test #'equal))
1471                   (let ((value (get-secondary-dispatch-function2
1472                                 gf methods types method-alist-p wrappers-p
1473                                 all-applicable-p all-sorted-p function-p)))
1474                     (push (cons akey value) (cdr ht-value))
1475                     value)))))))
1476
1477 (defun get-secondary-dispatch-function2 (gf methods types method-alist-p wrappers-p
1478                                             all-applicable-p all-sorted-p function-p)
1479   (if (and all-applicable-p all-sorted-p (not function-p))
1480       (if (eq *boot-state* 'complete)
1481           (let* ((combin (generic-function-method-combination gf))
1482                  (effective (compute-effective-method gf combin methods)))
1483             (make-effective-method-function1 gf effective method-alist-p wrappers-p))
1484           (let ((effective (standard-compute-effective-method gf nil methods)))
1485             (make-effective-method-function1 gf effective method-alist-p wrappers-p)))
1486       (let ((net (generate-discrimination-net
1487                   gf methods types all-sorted-p)))
1488         (compute-secondary-dispatch-function1 gf net function-p))))
1489
1490 (defun get-effective-method-function (gf methods &optional method-alist wrappers)
1491   (function-funcall (get-secondary-dispatch-function1 gf methods nil
1492                                                       (not (null method-alist))
1493                                                       (not (null wrappers))
1494                                                       t)
1495                     method-alist wrappers))
1496
1497 (defun get-effective-method-function1 (gf methods &optional (sorted-p t))
1498   (get-secondary-dispatch-function1 gf methods nil nil nil t sorted-p))
1499
1500 (defun methods-contain-eql-specializer-p (methods)
1501   (and (eq *boot-state* 'complete)
1502        (dolist (method methods nil)
1503          (when (dolist (spec (method-specializers method) nil)
1504                  (when (eql-specializer-p spec) (return t)))
1505            (return t)))))
1506 \f
1507 (defun update-dfun (generic-function &optional dfun cache info)
1508   (let* ((early-p (early-gf-p generic-function))
1509          (gf-name (if early-p
1510                       (early-gf-name generic-function)
1511                       (generic-function-name generic-function)))
1512          (ocache (gf-dfun-cache generic-function)))
1513     (set-dfun generic-function dfun cache info)
1514     (let* ((dfun (if early-p
1515                      (or dfun (make-initial-dfun generic-function))
1516                      (compute-discriminating-function generic-function)))
1517            (info (gf-dfun-info generic-function)))
1518       (unless (eq 'default-method-only (type-of info))
1519         (setq dfun (doctor-dfun-for-the-debugger
1520                     generic-function
1521                     dfun)))
1522       (set-funcallable-instance-function generic-function dfun)
1523       (set-function-name generic-function gf-name)
1524       (when (and ocache (not (eq ocache cache))) (free-cache ocache))
1525       dfun)))
1526 \f
1527 (defvar *dfun-count* nil)
1528 (defvar *dfun-list* nil)
1529 (defvar *minimum-cache-size-to-list*)
1530
1531 (defun list-dfun (gf)
1532   (let* ((sym (type-of (gf-dfun-info gf)))
1533          (a (assq sym *dfun-list*)))
1534     (unless a
1535       (push (setq a (list sym)) *dfun-list*))
1536     (push (generic-function-name gf) (cdr a))))
1537
1538 (defun list-all-dfuns ()
1539   (setq *dfun-list* nil)
1540   (map-all-generic-functions #'list-dfun)
1541   *dfun-list*)
1542
1543 (defun list-large-cache (gf)
1544   (let* ((sym (type-of (gf-dfun-info gf)))
1545          (cache (gf-dfun-cache gf)))
1546     (when cache
1547       (let ((size (cache-size cache)))
1548         (when (>= size *minimum-cache-size-to-list*)
1549           (let ((a (assoc size *dfun-list*)))
1550             (unless a
1551               (push (setq a (list size)) *dfun-list*))
1552             (push (let ((name (generic-function-name gf)))
1553                     (if (eq sym 'caching) name (list name sym)))
1554                   (cdr a))))))))
1555
1556 (defun list-large-caches (&optional (*minimum-cache-size-to-list* 130))
1557   (setq *dfun-list* nil)
1558   (map-all-generic-functions #'list-large-cache)
1559   (setq *dfun-list* (sort dfun-list #'< :key #'car))
1560   (mapc #'print *dfun-list*)
1561   (values))
1562
1563 (defun count-dfun (gf)
1564   (let* ((sym (type-of (gf-dfun-info gf)))
1565          (cache (gf-dfun-cache gf))
1566          (a (assq sym *dfun-count*)))
1567     (unless a
1568       (push (setq a (list sym 0 nil)) *dfun-count*))
1569     (incf (cadr a))
1570     (when cache
1571       (let* ((size (cache-size cache))
1572              (b (assoc size (third a))))
1573         (unless b
1574           (push (setq b (cons size 0)) (third a)))
1575         (incf (cdr b))))))
1576
1577 (defun count-all-dfuns ()
1578   (setq *dfun-count* (mapcar #'(lambda (type) (list type 0 nil))
1579                              '(ONE-CLASS TWO-CLASS DEFAULT-METHOD-ONLY
1580                                ONE-INDEX N-N CHECKING CACHING
1581                                DISPATCH)))
1582   (map-all-generic-functions #'count-dfun)
1583   (mapc #'(lambda (type+count+sizes)
1584             (setf (third type+count+sizes)
1585                   (sort (third type+count+sizes) #'< :key #'car)))
1586         *dfun-count*)
1587   (mapc #'(lambda (type+count+sizes)
1588             (format t "~&There are ~D dfuns of type ~S."
1589                     (cadr type+count+sizes) (car type+count+sizes))
1590             (format t "~%   ~S~%" (caddr type+count+sizes)))
1591         *dfun-count*)
1592   (values))
1593
1594 (defun gfs-of-type (type)
1595   (unless (consp type) (setq type (list type)))
1596   (let ((gf-list nil))
1597     (map-all-generic-functions #'(lambda (gf)
1598                                    (when (memq (type-of (gf-dfun-info gf)) type)
1599                                      (push gf gf-list))))
1600     gf-list))