%other-pointer-widetag derive-type: derive for simple-array.
[sbcl.git] / src / code / fdefinition.lisp
blob664c349cf8fa2aeaa3395d17cd4afc17b9d45d77
1 ;;;; This file contains functions that hack on the global function
2 ;;;; namespace (primarily concerned with SETF functions here). Also,
3 ;;;; function encapsulation and routines that set and return
4 ;;;; definitions disregarding whether they might be encapsulated.
6 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; more information.
8 ;;;;
9 ;;;; This software is derived from the CMU CL system, which was
10 ;;;; written at Carnegie Mellon University and released into the
11 ;;;; public domain. The software is in the public domain and is
12 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
13 ;;;; files for more information.
15 (in-package "SB-IMPL")
18 ;;;; fdefinition (fdefn) objects
20 (defun make-fdefn (name)
21 #-(and x86-64 immobile-space) (make-fdefn name)
22 #+(and x86-64 immobile-space)
23 (let ((fdefn (truly-the (values fdefn &optional)
24 (sb-vm::alloc-immobile-fdefn))))
25 (%primitive sb-vm::set-slot fdefn name 'make-fdefn
26 sb-vm:fdefn-name-slot sb-vm:other-pointer-lowtag)
27 (fdefn-makunbound fdefn)
28 fdefn))
30 (defun undo-static-linkage (fdefn) (declare (ignore fdefn)))
32 (defun (setf fdefn-fun) (fun fdefn)
33 (declare (type function fun)
34 (type fdefn fdefn))
35 (undo-static-linkage fdefn)
36 (sb-c::when-vop-existsp (:named sb-vm::set-fdefn-fun)
37 (%primitive sb-vm::set-fdefn-fun fun fdefn))
38 (sb-c::unless-vop-existsp (:named sb-vm::set-fdefn-fun)
39 (sb-vm::set-fdefn-fun fun fdefn))
40 fun)
42 ;;; Return the FDEFN object for NAME, or NIL if there is no fdefn.
43 ;;; Signal an error if name isn't valid.
44 ;;; Assume that exists-p implies LEGAL-FUN-NAME-P.
45 (declaim (ftype (sfunction ((or symbol list)) (or fdefn null)) find-fdefn))
46 (defun find-fdefn (name)
47 (declare (explicit-check))
48 (when (symbolp name) ; Don't need LEGAL-FUN-NAME-P check
49 (let ((fdefn (sb-vm::%symbol-fdefn name))) ; slot default is 0, not NIL
50 (return-from find-fdefn (if (eql fdefn 0) nil fdefn))))
51 ;; Technically the ALLOW-ATOM argument of NIL isn't needed, but
52 ;; the compiler isn't figuring out not to test SYMBOLP twice in a row.
53 (with-globaldb-name (key1 key2 nil) name
54 :hairy
55 (awhen (get-fancily-named-fdefn name nil)
56 (return-from find-fdefn it))
57 :simple
58 (progn
59 (awhen (symbol-dbinfo key1)
60 (multiple-value-bind (data-idx descriptor-idx field-idx)
61 (info-find-aux-key/packed it key2)
62 (declare (type index descriptor-idx)
63 (type (integer 0 #.+infos-per-word+) field-idx))
64 ;; Secondary names must have at least one info, so if a descriptor
65 ;; exists, there's no need to extract the n-infos field.
66 (when data-idx
67 (when (eql (incf field-idx) +infos-per-word+)
68 (setq field-idx 0 descriptor-idx (1+ descriptor-idx)))
69 (when (eql (packed-info-field it descriptor-idx field-idx)
70 +fdefn-info-num+)
71 (return-from find-fdefn
72 (%info-ref it (1- (the index data-idx))))))))
73 (when (eq key1 'setf) ; bypass the legality test
74 (return-from find-fdefn nil))))
75 (legal-fun-name-or-type-error name))
77 ;;; Return T if FUNCTION is the error-signaling trampoline for a macro or a
78 ;;; special operator. Test for this by seeing whether FUNCTION is the same
79 ;;; closure as for a known macro.
80 (declaim (inline macro/special-guard-fun-p))
81 (defun macro/special-guard-fun-p (function)
82 ;; When inlined, this is a few instructions shorter than CLOSUREP
83 ;; if we already know that FUNCTION is a function.
84 ;; It will signal a type error if not, which is the right thing to do anyway.
85 ;; (this isn't quite a true predicate)
86 (and (= (%fun-pointer-widetag function) sb-vm:closure-widetag)
87 ;; This test needs to reference the name of any macro, but in order for
88 ;; cold-init to work, the macro has to be defined first.
89 ;; So pick DX-LET, as it's in primordial-extensions.
90 ;; Prior to cold-init fixing up the load-time-value, this compares
91 ;; %closure-fun to 0, which is ok - it returns NIL.
92 (eq (load-time-value (%closure-fun (symbol-function 'dx-let)) t)
93 (%closure-fun function))))
95 ;;; This is the implementation of (COERCE s 'function) when S is of type symbol
96 ;;; used by either the full call or the compile-time transform for that pattern.
97 (defun coerce-symbol-to-fun (symbol)
98 (let ((def (%symbol-function symbol)))
99 (cond ((not def) (error 'undefined-function :name symbol))
100 ((macro/special-guard-fun-p def)
101 (error (ecase (car (%fun-name def))
102 (:macro "~S names a macro.")
103 (:special "~S names a special operator."))
104 symbol))
105 (t def))))
107 (defglobal *fdefn-of-nil* 0) ; God help you if you access this damn thing
108 (declaim (ftype (sfunction (t) fdefn) find-or-create-fdefn))
109 (defun find-or-create-fdefn (name)
110 (cond
111 ((symbolp name)
112 (let ((fdefn (sb-vm::%symbol-fdefn name)))
113 (if (or (eq fdefn nil) (eq fdefn 0))
114 (let* ((new (make-fdefn name))
115 (actual
116 (if name
117 (sb-vm::cas-symbol-fdefn name 0 new)
118 (cas *fdefn-of-nil* 0 new))))
119 (if (eql actual 0) new (the fdefn actual)))
120 fdefn)))
121 ((find-fdefn name))
123 ;; We won't reach here if the name was not legal
124 (let (made-new)
125 (dx-flet ((new (name)
126 (setq made-new t)
127 (make-fdefn name)))
128 (let ((fdefn (with-globaldb-name (key1 key2) name
129 :simple (get-info-value-initializing
130 :function :definition name (new name))
131 :hairy (get-fancily-named-fdefn name #'new))))
132 ;; Slot accessors spring into existence as soon as a reference
133 ;; is made to the respective fdefn, but we can't do this in
134 ;; (flet NEW) because ENSURE-ACCESSOR calls (SETF FDEFINITION)
135 ;; which would recurse, as the fdefn would not have been
136 ;; installed yet.
137 (when (and made-new
138 (typep name '(cons (eql sb-pcl::slot-accessor))))
139 (sb-pcl::ensure-accessor name))
140 fdefn))))))
142 ;;; Remove NAME's FTYPE information unless it was explicitly PROCLAIMED.
143 ;;; The NEW-FUNCTION argument is presently unused, but could be used
144 ;;; for checking compatibility of the NEW-FUNCTION against a proclamation.
145 ;;; (We could issue a warning and/or remove the type if incompatible.)
146 (defun maybe-clobber-ftype (name new-function)
147 (declare (ignore new-function))
148 ;; Ignore PCL-internal function names.
149 (unless (pcl-methodfn-name-p name)
150 (unless (eq :declared (info :function :where-from name))
151 (clear-info :function :type name))))
153 ;;; Return the fdefn-fun of NAME's fdefinition including any
154 ;;; encapsulations. This is the core of the implementation of the standard
155 ;;; FDEFINITION function, but as we've defined FDEFINITION, that
156 ;;; strips encapsulations.
157 (defun %coerce-name-to-fun (name)
158 (typecase name
159 ((and symbol (not null))
160 (let ((fun (%symbol-function name)))
161 (when (and fun (not (macro/special-guard-fun-p fun)))
162 (return-from %coerce-name-to-fun fun))))
163 (cons
164 (binding* ((fdefn (find-fdefn name) :exit-if-null)
165 (fun (fdefn-fun fdefn) :exit-if-null))
166 (return-from %coerce-name-to-fun fun))))
167 ;; We explicitly allow any function name when retrying,
168 ;; even if the erring caller was SYMBOL-FUNCTION. It is consistent
169 ;; that both #'(SETF MYNEWFUN) and '(SETF MYNEWFUN) are permitted
170 ;; as the object to use in the USE-VALUE restart.
171 (setq name (restart-case (if (legal-fun-name-p name)
172 (error 'undefined-function :name name)
173 (legal-fun-name-or-type-error name))
174 (continue ()
175 :report (lambda (stream)
176 (format stream "Retry using ~s." name))
177 name)
178 (use-value (value)
179 :report (lambda (stream)
180 (format stream "Use specified function"))
181 :interactive read-evaluated-form
182 (if (functionp value)
183 (return-from %coerce-name-to-fun value)
184 value))))
185 (%coerce-name-to-fun name))
187 ;; Coerce CALLABLE (a function-designator) to a FUNCTION.
188 ;; The compiler emits this when someone tries to FUNCALL something.
189 ;; Extended-function-designators are not accepted,
190 ;; This function declares EXPLICIT-CHECK, and we avoid calling
191 ;; SYMBOL-FUNCTION because that would do another check.
192 ;; It would be great if this could change its error message
193 ;; depending on the input to either:
194 ;; "foo is not a function designator" if not a CALLABLE
195 ;; "foo does not designate a currently defined function"
196 ;; if a symbol does not satisfy FBOUNDP.
197 (defun %coerce-callable-to-fun (callable)
198 (declare (explicit-check))
199 (typecase callable
200 (function
201 (return-from %coerce-callable-to-fun callable))
202 ((and symbol (not null)) ; NIL can't be fboundp. Quicker test this way.
203 (let ((fun (%symbol-function callable)))
204 (when (and fun (not (macro/special-guard-fun-p fun)))
205 (return-from %coerce-callable-to-fun fun))))
206 ;; If NIL, it's not technically a type-error, so instead hit the error
207 ;; in %coerce-name-to-fun which has a restart.
208 (null)
209 (t (error 'type-error :expected-type '(or symbol function) :datum callable)))
210 (%coerce-name-to-fun callable))
212 ;;; Behaves just like %COERCE-CALLABLE-TO-FUN but has an ir2-convert optimizer.
213 (setf (symbol-function '%coerce-callable-for-call) (symbol-function '%coerce-callable-to-fun))
216 ;;;; definition encapsulation
218 (defstruct (encapsulation-info (:constructor make-encapsulation-info
219 (type definition))
220 (:copier nil))
221 ;; This is definition's encapsulation type. The encapsulated
222 ;; definition is in the previous ENCAPSULATION-INFO element or
223 ;; installed as the global definition of some function name.
224 type
225 ;; the previous, encapsulated definition. This used to be installed
226 ;; as a global definition for some function name, but it was
227 ;; replaced by an encapsulation of type TYPE.
228 (definition nil :type function))
229 (declaim (freeze-type encapsulation-info))
231 ;;; Find the encapsulation info that has been closed over.
232 (defun encapsulation-info (fun)
233 (truly-the (or encapsulation-info null)
234 (when (closurep fun)
235 (find-if-in-closure #'encapsulation-info-p fun))))
237 (flet ((name->fun (name)
238 (typecase name
239 (symbol (%symbol-function name))
240 (t (binding* ((fdefn (find-fdefn name) :exit-if-null))
241 (fdefn-fun fdefn))))))
243 ;;; Does NAME have an encapsulation of the given TYPE?
244 (defun encapsulated-p (name type)
245 (let ((fun (name->fun name)))
246 (when (typep fun 'generic-function)
247 (return-from encapsulated-p (encapsulated-generic-function-p fun type)))
248 (do ((encap-info (encapsulation-info fun)
249 (encapsulation-info
250 (encapsulation-info-definition encap-info))))
251 ((null encap-info) nil)
252 (declare (type (or encapsulation-info null) encap-info))
253 (when (eq (encapsulation-info-type encap-info) type)
254 (return t)))))
256 ;;; Replace the definition of NAME with a function that calls FUNCTION
257 ;;; with the original function and its arguments.
258 ;;; TYPE is whatever you would like to associate with this
259 ;;; encapsulation for identification in case you need multiple
260 ;;; encapsulations of the same name.
261 (defun encapsulate (name type function)
262 (let ((underlying-fun (name->fun name)))
263 (when (macro/special-guard-fun-p underlying-fun)
264 (error "~S can not be encapsulated" name))
265 (if (typep underlying-fun 'generic-function)
266 (encapsulate-generic-function underlying-fun type function)
267 ;; We must bind and close over INFO. Consider the case where we
268 ;; encapsulate (the second) an encapsulated (the first)
269 ;; definition, and later someone unencapsulates the encapsulated
270 ;; (first) definition. We don't want our encapsulation (second) to
271 ;; bind basic-definition to the encapsulated (first) definition
272 ;; when it no longer exists. When unencapsulating, we make sure to
273 ;; clobber the appropriate INFO structure to allow
274 ;; basic-definition to be bound to the next definition instead of
275 ;; an encapsulation that no longer exists.
276 (let ((info (make-encapsulation-info type underlying-fun)))
277 (setf (fdefn-fun (find-fdefn name))
278 (named-lambda encapsulation (&rest args)
279 (apply function (encapsulation-info-definition info)
280 args)))))))
282 ;;; When removing an encapsulation, we must remember that
283 ;;; encapsulating definitions close over a reference to the
284 ;;; ENCAPSULATION-INFO that describes the encapsulating definition.
285 ;;; When you find an info with the target type, the previous info in
286 ;;; the chain has the ensulating definition of that type. We take the
287 ;;; encapsulated definition from the info with the target type, and we
288 ;;; store it in the previous info structure whose encapsulating
289 ;;; definition it describes looks to this previous info structure for
290 ;;; a definition to bind (see ENCAPSULATE). When removing the first
291 ;;; info structure, we do something conceptually equal, but
292 ;;; mechanically it is different.
293 (defun unencapsulate (name type)
294 "Removes NAME's outermost encapsulation of the specified TYPE."
295 (let* ((fun (name->fun name))
296 (encap-info (encapsulation-info fun)))
297 (cond ((typep fun 'generic-function)
298 (unencapsulate-generic-function fun type))
299 ((not encap-info)
300 ;; It disappeared on us, so don't worry about it.
302 ((eq (encapsulation-info-type encap-info) type)
303 ;; It's the first one, so change the fdefn object.
304 (setf (fdefn-fun (find-fdefn name))
305 (encapsulation-info-definition encap-info)))
307 ;; It must be an interior one, so find it.
308 (loop
309 (let ((next-info (encapsulation-info
310 (encapsulation-info-definition encap-info))))
311 (unless next-info
312 ;; Not there, so don't worry about it.
313 (return))
314 (when (eq (encapsulation-info-type next-info) type)
315 ;; This is it, so unlink us.
316 (setf (encapsulation-info-definition encap-info)
317 (encapsulation-info-definition next-info))
318 (return))
319 (setf encap-info next-info))))))
323 ;;;; FDEFINITION
325 ;;; KLUDGE: Er, it looks as though this means that
326 ;;; (FUNCALL (FDEFINITION 'FOO))
327 ;;; doesn't do the same thing as
328 ;;; (FUNCALL 'FOO),
329 ;;; and (SYMBOL-FUNCTION 'FOO) isn't in general the same thing
330 ;;; as (FDEFINITION 'FOO). That doesn't look like ANSI behavior to me.
331 ;;; Look e.g. at the ANSI definition of TRACE: "Whenever a traced
332 ;;; function is invoked, information about the call, ..". Try this:
333 ;;; (DEFUN FOO () (PRINT "foo"))
334 ;;; (TRACE FOO)
335 ;;; (FUNCALL 'FOO)
336 ;;; (FUNCALL (FDEFINITION 'FOO))
337 ;;; What to do? ANSI says TRACE "Might change the definitions of the
338 ;;; functions named by function-names." Might it be OK to just get
339 ;;; punt all this encapsulation stuff and go back to a simple but
340 ;;; correct implementation of TRACE? We'd lose the ability to redefine
341 ;;; a TRACEd function and keep the trace in place, but that seems
342 ;;; tolerable to me. (Is the wrapper stuff needed for anything else
343 ;;; besides TRACE?)
345 ;;; The only problem I can see with not having a wrapper: If tracing
346 ;;; EQ, EQL, EQUAL, or EQUALP causes its function address to change,
347 ;;; it will mess up the MAKE-HASH-TABLE logic which uses EQ tests
348 ;;; on those function values. But given the ANSI statement about
349 ;;; TRACE causing things to change, that doesn't seem too unreasonable;
350 ;;; and we might even be able to forbid tracing these functions.
351 ;;; -- WHN 2001-11-02
352 (defun fdefinition (name)
353 "Return name's global function definition taking care to respect any
354 encapsulations and to return the innermost encapsulated definition.
355 This is SETF'able."
356 (declare (explicit-check))
357 ;; %COERCE-NAME-TO-FUN signals an error for macros and special operators,
358 ;; but FDEFINITION should not, so pick off symbols using %SYMBOL-FUNCTION.
359 (strip-encapsulation (or (and (symbolp name) (%symbol-function name))
360 (%coerce-name-to-fun name))))
361 (defun strip-encapsulation (fun)
362 (loop
363 (let ((encap-info (encapsulation-info fun)))
364 (if encap-info
365 (setf fun (encapsulation-info-definition encap-info))
366 (return fun)))))
368 (define-load-time-global *setf-fdefinition-hook* nil
369 "A list of functions that (SETF FDEFINITION) invokes before storing the
370 new value. The functions take the function name and the new value.")
372 ;; Reject any "object of implementation-dependent nature" that
373 ;; so happens to be a function in SBCL, but which must not be
374 ;; bound to a function-name by way of (SETF FEDFINITION).
375 (defun err-if-unacceptable-function (object setter)
376 (when (macro/special-guard-fun-p object)
377 (error 'simple-reference-error
378 :references '((:ansi-cl :function fdefinition))
379 :format-control "~S is not acceptable to ~S."
380 :format-arguments (list object setter))))
382 (defun (setf fdefinition) (new-value name)
383 "Set NAME's global function definition."
384 (declare (type function new-value) (optimize (safety 1)))
385 (declare (explicit-check))
386 (err-if-unacceptable-function new-value '(setf fdefinition))
387 (setq new-value (strip-encapsulation new-value))
388 (with-single-package-locked-error (:symbol name "setting fdefinition of ~A")
389 (maybe-clobber-ftype name new-value)
391 ;; Check for hash-table stuff. Woe onto him that mixes encapsulation
392 ;; with this.
393 (when (symbolp name)
394 (let ((old (%symbol-function name)))
395 (dolist (spec *user-hash-table-tests*)
396 (cond ((eq old (second spec))
397 ;; test-function
398 (setf (second spec) new-value))
399 ((eq old (third spec))
400 ;; hash-function
401 (setf (third spec) new-value))))))
403 (let ((fdefn (find-or-create-fdefn name)))
404 (dolist (f *setf-fdefinition-hook*)
405 (declare (type function f))
406 (funcall f name new-value))
407 (let ((encap-info (encapsulation-info (fdefn-fun fdefn))))
408 (cond (encap-info
409 (loop
410 (let ((more-info
411 (encapsulation-info
412 (encapsulation-info-definition encap-info))))
413 (if more-info
414 (setf encap-info more-info)
415 (return (setf (encapsulation-info-definition encap-info)
416 new-value))))))
418 (setf (fdefn-fun fdefn) new-value)))))))
420 ;;;; FBOUNDP and FMAKUNBOUND
422 (defun fboundp (name)
423 "Return true if name has a global function definition."
424 (declare (explicit-check))
425 (awhen (find-fdefn name) (fdefn-fun it)))
427 (defun fmakunbound (name)
428 "Make NAME have no global function definition."
429 (declare (explicit-check))
430 (with-single-package-locked-error
431 (:symbol name "removing the function or macro definition of ~A")
432 (let ((fdefn (find-fdefn name)))
433 (when fdefn
434 (undo-static-linkage fdefn)
435 (fdefn-makunbound fdefn)))
436 (undefine-fun-name name)
437 name))
439 ;;; A simple open-addressing hashset.
440 (define-load-time-global *fdefns*
441 (cons (make-array 128 :initial-element 0) 0))
442 (define-load-time-global *fdefns-lock* (sb-thread:make-mutex :name "fdefns"))
444 ;;; Fancily named fdefns are not attached to symbols, but instead in a custom
445 ;;; data structure which we probe in the manner of a quadratic probing hash-table.
446 ;;; A max load factor ensures that probing terminates.
447 ;;; https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/
448 ;;; contains a proof that triangular numbers mod 2^N visit every cell.
450 ;;; The intent here - which may be impossible to realize - was to allow garbage-collection
451 ;;; of FDEFNs whose name is not reachable. I couldn't get it to do the right thing.
452 ;;; e.g. (defmethod foo (x (y cons)) ...) creates mappings:
453 ;;; (SB-PCL::FAST-METHOD FOO (T CONS)) -> #<SB-KERNEL:FDEFN (SB-PCL::FAST-METHOD FOO (T CONS))>
454 ;;; (SB-PCL::SLOW-METHOD FOO (T CONS)) -> #<SB-KERNEL:FDEFN (SB-PCL::SLOW-METHOD FOO (T CONS))>
455 ;;; where it seems like (unintern 'FOO) should allow both of those to get GCd.
456 ;;; I suspect that it will require hanging those fancily named fdefns off the symbol
457 ;;; FOO rather than having a global table. Alternatively, that can be simulated by
458 ;;; having GC preserve liveness of any element whenever the second item in the list
459 ;;; comprising fdefn-name is an a-priori live symbol. That will be more efficient than
460 ;;; having a hash-table hanging off every symbol that names a method.
461 ;;; e.g. both of the preceding names would be hanging off of FOO, as would others
462 ;;; such as (FAST-METHOD FOO :AROUND (LIST INTEGER)) and a myriad of others.
463 ;;; I suspect that any approach of hanging off the symbols will be space-inefficient
464 ;;; and difficult to implement.
466 ;;; At any rate, we can make use of the key-in-value nature of fdefns to halve
467 ;;; the number of words required to store the name -> object mapping.
468 (defun get-fancily-named-fdefn (name constructor &aux (hash (globaldb-sxhashoid name)))
469 (declare (type (or function null) constructor))
470 (labels ((lookup (vector &aux (mask (1- (length vector)))
471 (index (logand hash mask))
472 (step 0)
473 (empty-cell nil))
474 ;; Because rehash is forced well before the table becomes 100% full,
475 ;; it should not be possible to loop infinitely here.
476 (loop (let ((fdefn (svref vector index)))
477 (cond ((eql fdefn 0) ; not found
478 (return-from lookup (or empty-cell index)))
479 #+nil ((eql fdefn nil) ; smashed by GC
480 (unless empty-cell (setq empty-cell index)))
481 ((equal (fdefn-name fdefn) name)
482 (return-from lookup fdefn))))
483 (setq index (logand (+ index (incf step)) mask))))
484 (insert (hash item vector mask &aux (index (logand hash mask))
485 (step 0)
486 (empty-cell nil))
487 (loop (case (svref vector index)
488 ((0) ; not found
489 (return (setf (svref vector (or empty-cell index)) item)))
490 #+nil ((nil) ; smashed by GC
491 (unless empty-cell (setq empty-cell index))))
492 (setq index (logand (+ index (incf step)) mask)))))
493 (or (let ((result (lookup (car *fdefns*))))
494 (when (fdefn-p result) result))
495 (when constructor ; double-check w/lock before inserting
496 (with-system-mutex (*fdefns-lock*)
497 (let* ((fdefns *fdefns*)
498 (vector (car fdefns))
499 (result (lookup vector)))
500 (if (fdefn-p result)
501 result
502 (let ((new-fdefn (funcall constructor name)))
503 (if (<= (incf (cdr fdefns)) (ash (length vector) -1)) ; under 50% full
504 ;; It might even be less full than that due to GC.
505 (setf (svref vector result) new-fdefn)
506 ;; The actual count is unknown without re-counting.
507 (let* ((count (count-if #'fdefn-p vector))
508 (new-size (power-of-two-ceiling
509 (ceiling (* count 2))))
510 (new-vect (make-array new-size :initial-element 0))
511 (new-mask (1- new-size)))
512 (dovector (item vector)
513 (when (fdefn-p item)
514 (insert (globaldb-sxhashoid (fdefn-name item)) item
515 new-vect new-mask)))
516 (insert hash new-fdefn new-vect new-mask)
517 (setf *fdefns* (cons new-vect (1+ count)))))
518 new-fdefn))))))))