d4bc004e88c05f7dd719cb9a464325e2d853ced3
[sbcl.git] / doc / internals / discriminating-functions.texinfo
1 @node Discriminating Functions
2 @comment  node-name,  next,  previous,  up
3 @chapter Discriminating Functions
4
5 @menu
6 * The Initial Discriminating Function::
7 * Method-Based Discriminating Functions::
8 * Accessor Discriminating Functions::
9 * Cacheing and Dispatch Functions::
10 * The Cacheing Mechanism::
11 @end menu
12
13 The Common Lisp Object System specifies a great deal of run-time
14 customizeability, such as class redefinition, generic function and
15 method redefinition, addition and removal of methods and redefinitions
16 of method combinations.  The additional flexibility defined by the
17 Metaobject Protocol, specifying the generic functions called to achieve
18 the effects of CLOS operations (and allowing many of them to be
19 overridden by the user) makes any form of optimization seem intractable.
20 And yet such optimization is necessary to achieve reasonable
21 performance: the MOP specifies that a slot access looks up the class of
22 the object, and the slot definition from that class and the slot name,
23 and then invokes a generic function specialized on those three
24 arguments.  This is clearly going to act against the user's intuition
25 that a slot access given an instance should be relatively fast.
26
27 The optimizations performed cannot be done wholly at compile-time,
28 however, thanks to all of these possibilities for run-time redefinition
29 and extensibility.  This section describes the optimizations performed
30 in SBCL's CLOS implementation in computing and calling the effective
31 method for generic functions.
32
33 @node The Initial Discriminating Function
34 @comment  node-name,  next,  previous,  up
35 @section The Initial Discriminating Function
36
37 @findex compute-discriminating-function
38 @findex sb-mop:compute-discriminating-function
39
40 The system method on @code{SB-MOP:COMPUTE-DISCRIMINATING-FUNCTION},
41 under most circumstances, returns a function which closes over a
42 structure of type @code{SB-PCL::INITIAL}, and which calls
43 @code{SB-PCL::INITIAL-DFUN}.  This discriminating function is
44 responsible for implementing the computation of the applicable methods,
45 the effective method, and thence the result of the call to the generic
46 function.  In addition, it implements optimization of these steps, based
47 on the arguments it has been called with since the discriminating
48 function was installed and the methods of the generic function.
49
50 @float Figure,fig:dfun-transitions
51 @image{discriminating-functions}
52 @end float
53
54 For each substantive change of the generic function (such as addition or
55 removal of a method, or other reinitialization) the discriminating
56 function is reset to its initial state.
57
58 The initial discriminating function can transition into a discriminating
59 function optimized for the methods on the generic function
60 (@code{SB-PCL::NO-METHODS}, @code{SB-PCL::DEFAULT-METHOD-ONLY},
61 @code{SB-PCL::CONSTANT-VALUE}), for slot access
62 (@code{SB-PCL::ONE-CLASS}, @code{SB-PCL::TWO-CLASS},
63 @code{SB-PCL::ONE-INDEX}, @code{SB-PCL::N-N}@footnote{Would be better
64 named as @code{M-N}.}), or for dispatch based on its arguments
65 (@code{SB-PCL::CACHING}, @code{SB-PCL::DISPATCH}).  Those in the second
66 category can transition into the third, or into a
67 @code{SB-PCL::CHECKING} state where the choice between
68 @code{SB-PCL::CACHING} and @code{SB-PCL::DISPATCH} has not yet been
69 made.
70
71 The possible transitions are shown in @ref{fig:dfun-transitions}.
72
73 @node Method-Based Discriminating Functions
74 @comment  node-name,  next,  previous,  up
75 @section Method-Based Discriminating Functions
76
77 @findex no-applicable-method
78
79 The method-based discriminating functions are used if all the methods of
80 the generic function at the time of the first call are suitable:
81 therefore, these discriminating function strategies do not transition
82 into any of the other states unless the generic function is
83 reinitialized.  Of these discriminating functions, the simplest is the
84 @code{SB-PCL::NO-METHODS}, which is appropriate when the generic
85 function has no methods.  In this case, the discriminating function
86 simply performs an argument count check@footnote{Actually, this bit
87 isn't currently done.  Oops.} and then calls
88 @code{NO-APPLICABLE-METHOD} with the appropriate arguments.
89
90 If all of the specializers in all methods of the generic function are
91 the root of the class hierarchy, @code{t}, then no discrimination need
92 be performed: all of the methods are applicable on every
93 call@footnote{Hm, there might be another problem with argument count
94 here.}.  In this case, the @code{SB-PCL::DEFAULT-METHOD-ONLY}
95 discriminating function can call the effective method directly, as it
96 will be the same for every generic function call.@footnote{I wonder if
97 we're invalidating this right if we define a method on
98 compute-applicable-methods...}
99
100 If all methods of the generic function are known by the system to be
101 side-effect-free and return constants, and the generic function has
102 standard-method-combination and no eql-specialized methods, then the
103 @code{SB-PCL::CONSTANT-VALUE} discriminating function can simply cache
104 the return values for given argument types.  Though this may initially
105 appear to have limited applicability, type predicates are usually of
106 this form, as in @ref{ex:pred}@footnote{There is vestigial code in SBCL
107 for a currently unused specialization of @code{SB-PCL::CONSTANT-VALUE}
108 for boolean values only.}.
109
110 @float Example,ex:pred
111 @example
112 (defgeneric foop (x))
113 (defmethod foop ((foo foo)) t)
114 (defmethod foop (object) nil)
115 @end example
116 @end float
117
118 More details of the cacheing mechanism are given in @ref{The Cacheing
119 Mechanism} below.
120
121 @node Accessor Discriminating Functions
122 @comment  node-name,  next,  previous,  up
123 @section Accessor Discriminating Functions
124
125 Accessor Discriminating Functions are used when the effective method of
126 all calls is an access to a slot, either reading, writing or checking
127 boundness@footnote{Although there is ordinarily no way for a user to
128 define a boundp method, some automatically generated generic functions
129 have them}; for this path to apply, there must be no non-standard
130 methods on @code{SB-MOP:SLOT-VALUE-USING-CLASS} and its siblings.  The
131 first state is @code{SB-PCL::ONE-CLASS}, entered when one class of
132 instance has been accessed; the discriminating function here closes over
133 the wrapper of the class and the slot index, and accesses the slot of
134 the instance directly.  
135
136 If a direct instance of another class is passed to the generic function
137 for slot access, then another accessor discriminating function is
138 created: if the index of the slot in the slots vector of each instance
139 is the same, then a @code{SB-PCL::TWO-CLASS} function is created,
140 closing over the two class wrappers and the index and performing the
141 simple dispatch.  If the slot indexes are not the same, then we go to
142 the @code{SB-PCL::N-N} state.
143
144 For slot accesses for more than two classes with the same index, we move
145 to the @code{SB-PCL::ONE-INDEX} state which maintains a cache of
146 wrappers for which the slot index is the same.  If at any point the slot
147 index for an instance is not the same, the state moves to
148 @code{SB-PCL::N-N}, which maintains a cache of wrappers and their
149 associated indexes; if at any point an effective method which is not a
150 simple slot access is encountered, then the discriminating function
151 moves into the @code{SB-PCL::CHECKING}, @code{SB-PCL::CACHING} or
152 @code{SB-PCL::DISPATCH} states.
153
154 @node Cacheing and Dispatch Functions
155 @comment  node-name,  next,  previous,  up
156 @section Cacheing and Dispatch Functions
157
158 @code{SB-PCL::CACHING} functions simply cache effective methods as a
159 function of argument wrappers, while @code{SB-PCL::DISPATCH} functions
160 have code that computes the actual dispatch.  @code{SB-PCL::CHECKING}
161 functions have a cache, but on cache misses will recompute whether or
162 not to generate a @code{SB-PCL::CACHING} or @code{SB-PCL::DISPATCH}
163 function.
164
165 (FIXME: I'm actually not certain about the above paragraph.  Read the
166 code again and see if it makes any more sense.)
167
168 @node The Cacheing Mechanism
169 @comment  node-name,  next,  previous,  up
170 @section The Cacheing Mechanism
171
172 In general, the cacheing mechanism works as follows: each class has an
173 associated wrapper, with some number of uniformly-distributed random
174 hash values associated with it; each cache has an associated index into
175 this pseudovector of random hash values.  To look a value up from a
176 cache from a single class, the hash corresponding to the cache's index
177 is looked up and reduced to the size of the cache (by bitmasking, for
178 cache sizes of a power of two); then the entry at that index is looked
179 up and compared for indentity with the wrapper in question.  If it
180 matches, this is a hit; otherwise the cache is walked sequentially from
181 this index, skipping the 0th entry.  If the original index is reached,
182 the cache does not contain the value sought@footnote{Actually, there's
183 some kind of scope for overflow.}.
184
185 To add an entry to a cache, much the same computation is executed.
186 However, if there is a collision in hash values, before the cache is
187 grown, an attempt is made to fill the cache using a different index into
188 the wrappers' hash values.
189
190 Wrappers are invalidated for caches by setting all of their hash values
191 to zero.  (Additionally, they are invalidated by setting their
192 @code{depthoid} to -1, to communicate to structure type testers, and
193 their @code{invalid} to non-@code{nil}, communicating to
194 @code{obsolete-instance-trap}.
195
196 The hash value for multiple dispatch is computed by summing all of the
197 individual hash values from each wrapper (excluding arguments for which
198 all methods have @code{t} specializers, for which no dispatch
199 computation needs to be done), jumping to the cache miss case if any
200 wrapper has a zero hash index.
201
202 (FIXME: As of sbcl-0.9.x.y, the generality of multiple hash values per
203 wrapper was removed, as it appeared to do nothing in particular for
204 performance in real-world situations.)
205
206 References (O for working BibTeX):
207
208 The CLOS standards proposal
209
210 Kiczales and Rodruigez
211
212 AMOP