Make globaldb's mapping from a CLOS specializer to its CTYPE transparent.
[sbcl.git] / contrib / sb-introspect / introspect.lisp
blob09ae5c5249e55cf790085f97333561b556688b9a
1 ;;; introspection library
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 ;;; For the avoidance of doubt, the exported interface is the supported
13 ;;; interface. Anything else is internal, though you're welcome to argue a
14 ;;; case for exporting it.
16 ;;; If you steal the code from this file to cut and paste into your
17 ;;; own project, there will be much wailing and gnashing of teeth.
18 ;;; Your teeth. If need be, we'll kick them for you. This is a
19 ;;; contrib, we're allowed to look in internals. You're an
20 ;;; application programmer, and are not.
22 ;;; TODO
23 ;;; 1) structs don't have within-file location info. problem for the
24 ;;; structure itself, accessors, the copier and the predicate
25 ;;; 3) error handling. Signal random errors, or handle and resignal 'our'
26 ;;; error, or return NIL?
27 ;;; 4) FIXMEs
29 (defpackage :sb-introspect
30 (:use "CL")
31 (:export "ALLOCATION-INFORMATION"
32 "FUNCTION-ARGLIST"
33 "FUNCTION-LAMBDA-LIST"
34 "FUNCTION-TYPE"
35 "DEFTYPE-LAMBDA-LIST"
36 "VALID-FUNCTION-NAME-P"
37 "FIND-DEFINITION-SOURCE"
38 "FIND-DEFINITION-SOURCES-BY-NAME"
39 "DEFINITION-SOURCE"
40 "DEFINITION-SOURCE-PATHNAME"
41 "DEFINITION-SOURCE-FORM-PATH"
42 "DEFINITION-SOURCE-CHARACTER-OFFSET"
43 "DEFINITION-SOURCE-FILE-WRITE-DATE"
44 "DEFINITION-SOURCE-PLIST"
45 "FIND-FUNCTION-CALLEES"
46 "FIND-FUNCTION-CALLERS"
47 "MAP-ROOT"
48 "WHO-BINDS"
49 "WHO-CALLS"
50 "WHO-REFERENCES"
51 "WHO-SETS"
52 "WHO-MACROEXPANDS"
53 "WHO-SPECIALIZES-DIRECTLY"
54 "WHO-SPECIALIZES-GENERALLY"))
56 (in-package :sb-introspect)
58 ;;;; Internal interface for SBCL debug info
60 ;;; Here are some tutorial-style type definitions to help understand
61 ;;; the internal SBCL debugging data structures we're using. The
62 ;;; commentary is based on CMUCL's debug internals manual.
63 ;;;
64 (deftype debug-info ()
65 "Structure containing all the debug information related to a function.
66 Function objects reference debug-infos which in turn reference
67 debug-sources and so on."
68 'sb-c::compiled-debug-info)
70 (deftype debug-source ()
71 "Debug sources describe where to find source code.
72 For example, the debug source for a function compiled from a file will
73 include the pathname of the file and the position of the definition."
74 'sb-c::debug-source)
76 (deftype debug-function ()
77 "Debug function represent static compile-time information about a function."
78 'sb-c::compiled-debug-fun)
80 (declaim (ftype (function (function) debug-info) function-debug-info))
81 (defun function-debug-info (function)
82 (let* ((function-object (sb-kernel::%fun-fun function))
83 (function-header (sb-kernel:fun-code-header function-object)))
84 (sb-kernel:%code-debug-info function-header)))
86 (declaim (ftype (function (function) debug-source) function-debug-source))
87 (defun function-debug-source (function)
88 (debug-info-source (function-debug-info function)))
90 (declaim (ftype (function (debug-info) debug-source) debug-info-source))
91 (defun debug-info-source (debug-info)
92 (sb-c::debug-info-source debug-info))
94 (declaim (ftype (function (debug-info) debug-function) debug-info-debug-function))
95 (defun debug-info-debug-function (debug-info)
96 (elt (sb-c::compiled-debug-info-fun-map debug-info) 0))
98 (defun valid-function-name-p (name)
99 "True if NAME denotes a valid function name, ie. one that can be passed to
100 FBOUNDP."
101 (and (sb-int:valid-function-name-p name) t))
103 ;;;; Finding definitions
105 (defstruct definition-source
106 ;; Pathname of the source file that the definition was compiled from.
107 ;; This is null if the definition was not compiled from a file.
108 (pathname nil :type (or null pathname))
109 ;; Source-path of the definition within the file.
110 ;; This may be incomplete depending on the debug level at which the
111 ;; source was compiled.
112 (form-path '() :type list)
113 ;; Character offset of the top-level-form containing the definition.
114 ;; This corresponds to the first element of form-path.
115 (character-offset nil :type (or null integer))
116 ;; File-write-date of the source file when compiled.
117 ;; Null if not compiled from a file.
118 (file-write-date nil :type (or null integer))
119 ;; plist from WITH-COMPILATION-UNIT
120 (plist nil)
121 ;; Any extra metadata that the caller might be interested in. For
122 ;; example the specializers of the method whose definition-source this
123 ;; is.
124 (description nil :type list))
126 (defun vop-sources-from-fun-templates (name)
127 (let ((fun-info (sb-int:info :function :info name)))
128 (when fun-info
129 (loop for vop in (sb-c::fun-info-templates fun-info)
130 for source = (find-definition-source
131 (sb-c::vop-info-generator-function vop))
132 do (setf (definition-source-description source)
133 (list (sb-c::template-name vop)
134 (sb-c::template-note vop)))
135 collect source))))
137 (defun find-vop-source (name)
138 (let* ((templates (vop-sources-from-fun-templates name))
139 (vop (gethash name sb-c::*backend-template-names*))
140 (generator (when vop
141 (sb-c::vop-info-generator-function vop)))
142 (source (when generator
143 (find-definition-source generator))))
144 (cond
145 (source
146 (setf (definition-source-description source)
147 (list name))
148 (cons source templates))
150 templates))))
152 (defun find-definition-sources-by-name (name type)
153 "Returns a list of DEFINITION-SOURCEs for the objects of type TYPE
154 defined with name NAME. NAME may be a symbol or a extended function
155 name. Type can currently be one of the following:
157 (Public)
158 :CLASS
159 :COMPILER-MACRO
160 :CONDITION
161 :CONSTANT
162 :FUNCTION
163 :GENERIC-FUNCTION
164 :MACRO
165 :METHOD
166 :METHOD-COMBINATION
167 :PACKAGE
168 :SETF-EXPANDER
169 :STRUCTURE
170 :SYMBOL-MACRO
171 :TYPE
172 :VARIABLE
174 (Internal)
175 :OPTIMIZER
176 :SOURCE-TRANSFORM
177 :TRANSFORM
178 :VOP
180 If an unsupported TYPE is requested, the function will return NIL.
182 (flet ((listify (x)
183 (if (listp x)
185 (list x)))
186 (get-class (name)
187 (and (symbolp name)
188 (find-class name nil)))
189 (real-fdefinition (name)
190 ;; for getting the real function object, even if the
191 ;; function is being profiled
192 (let ((profile-info (gethash name sb-profile::*profiled-fun-name->info*)))
193 (if profile-info
194 (sb-profile::profile-info-encapsulated-fun profile-info)
195 (fdefinition name)))))
196 (listify
197 (case type
198 ((:variable)
199 (when (and (symbolp name)
200 (member (sb-int:info :variable :kind name)
201 '(:global :special)))
202 (translate-source-location (sb-int:info :source-location type name))))
203 ((:constant)
204 (when (and (symbolp name)
205 (eq (sb-int:info :variable :kind name) :constant))
206 (translate-source-location (sb-int:info :source-location type name))))
207 ((:symbol-macro)
208 (when (and (symbolp name)
209 (eq (sb-int:info :variable :kind name) :macro))
210 (translate-source-location (sb-int:info :source-location type name))))
211 ((:macro)
212 (when (and (symbolp name)
213 (macro-function name))
214 (find-definition-source (macro-function name))))
215 ((:compiler-macro)
216 (when (compiler-macro-function name)
217 (find-definition-source (compiler-macro-function name))))
218 ((:function :generic-function)
219 (when (and (fboundp name)
220 (or (not (symbolp name))
221 (not (macro-function name))
222 (special-operator-p name)))
223 (let ((fun (real-fdefinition name)))
224 (when (eq (not (typep fun 'generic-function))
225 (not (eq type :generic-function)))
226 (find-definition-source fun)))))
227 ((:type)
228 ;; Source locations for types are saved separately when the expander
229 ;; is a closure without a good source-location.
230 (let ((loc (sb-int:info :type :source-location name)))
231 (if loc
232 (translate-source-location loc)
233 (let ((expander-fun (sb-int:info :type :expander name)))
234 (when expander-fun
235 (find-definition-source expander-fun))))))
236 ((:method)
237 (when (fboundp name)
238 (let ((fun (real-fdefinition name)))
239 (when (typep fun 'generic-function)
240 (loop for method in (sb-mop::generic-function-methods
241 fun)
242 for source = (find-definition-source method)
243 when source collect source)))))
244 ((:setf-expander)
245 (when (and (consp name)
246 (eq (car name) 'setf))
247 (setf name (cadr name)))
248 (let ((expander (or (sb-int:info :setf :inverse name)
249 (sb-int:info :setf :expander name))))
250 (when expander
251 (find-definition-source (if (symbolp expander)
252 (symbol-function expander)
253 expander)))))
254 ((:structure)
255 (let ((class (get-class name)))
256 (if class
257 (when (typep class 'sb-pcl::structure-class)
258 (find-definition-source class))
259 (when (sb-int:info :typed-structure :info name)
260 (translate-source-location
261 (sb-int:info :source-location :typed-structure name))))))
262 ((:condition :class)
263 (let ((class (get-class name)))
264 (when (and class
265 (not (typep class 'sb-pcl::structure-class)))
266 (when (eq (not (typep class 'sb-pcl::condition-class))
267 (not (eq type :condition)))
268 (find-definition-source class)))))
269 ((:method-combination)
270 (let ((combination-fun
271 (find-method #'sb-mop:find-method-combination
273 (list (find-class 'generic-function)
274 (list 'eql name)
276 nil)))
277 (when combination-fun
278 (find-definition-source combination-fun))))
279 ((:package)
280 (when (symbolp name)
281 (let ((package (find-package name)))
282 (when package
283 (find-definition-source package)))))
284 ;; TRANSFORM and OPTIMIZER handling from swank-sbcl
285 ((:transform)
286 (when (symbolp name)
287 (let ((fun-info (sb-int:info :function :info name)))
288 (when fun-info
289 (loop for xform in (sb-c::fun-info-transforms fun-info)
290 for source = (find-definition-source
291 (sb-c::transform-function xform))
292 for typespec = (sb-kernel:type-specifier
293 (sb-c::transform-type xform))
294 for note = (sb-c::transform-note xform)
295 do (setf (definition-source-description source)
296 (if (consp typespec)
297 (list (second typespec) note)
298 (list note)))
299 collect source)))))
300 ((:optimizer)
301 (let ((fun-info (and (symbolp name)
302 (sb-int:info :function :info name))))
303 (when fun-info
304 (let ((otypes '((sb-c:fun-info-derive-type . sb-c:derive-type)
305 (sb-c:fun-info-ltn-annotate . sb-c:ltn-annotate)
306 (sb-c:fun-info-optimizer . sb-c:optimizer)
307 (sb-c:fun-info-ir2-convert . sb-c:ir2-convert)
308 (sb-c::fun-info-stack-allocate-result
309 . sb-c::stack-allocate-result))))
310 (loop for (reader . name) in otypes
311 for fn = (funcall reader fun-info)
312 when fn collect
313 (let ((source (find-definition-source fn)))
314 (setf (definition-source-description source)
315 (list name))
316 source))))))
317 ((:vop)
318 (when (symbolp name)
319 (find-vop-source name)))
320 ((:source-transform)
321 (let* ((transform-fun
322 (or (sb-int:info :function :source-transform name)
323 (and (typep name '(cons (eql setf) (cons symbol null)))
324 (sb-int:info :function :source-transform
325 (second name)))))
326 ;; A cons for the :source-transform is essentially the same
327 ;; info that was formerly in :structure-accessor.
328 (accessor (and (consp transform-fun) (cdr transform-fun))))
329 ;; Structure accessors have source transforms, but the
330 ;; returned locations will neither show the actual place
331 ;; where it's defined, nor is really interesting.
332 (when (and transform-fun
333 (not accessor))
334 (find-definition-source transform-fun))))
336 nil)))))
338 (defun find-definition-source (object)
339 (typecase object
340 ((or sb-pcl::condition-class sb-pcl::structure-class)
341 (let ((classoid (sb-impl::find-classoid (class-name object))))
342 (when classoid
343 (let ((layout (sb-impl::classoid-layout classoid)))
344 (when layout
345 (translate-source-location
346 (sb-kernel::layout-source-location layout)))))))
347 (method-combination
348 (car
349 (find-definition-sources-by-name
350 (sb-pcl::method-combination-type-name object) :method-combination)))
351 (package
352 (translate-source-location (sb-impl::package-source-location object)))
353 (class
354 (translate-source-location (sb-pcl::definition-source object)))
355 ;; Use the PCL definition location information instead of the function
356 ;; debug-info for methods and generic functions. Sometimes the
357 ;; debug-info would point into PCL internals instead of the proper
358 ;; location.
359 (generic-function
360 (let ((source (translate-source-location
361 (sb-pcl::definition-source object))))
362 (when source
363 (setf (definition-source-description source)
364 (list (sb-mop:generic-function-lambda-list object))))
365 source))
366 (method
367 (let ((source (translate-source-location
368 (sb-pcl::definition-source object))))
369 (when source
370 (setf (definition-source-description source)
371 (append (method-qualifiers object)
372 (if (sb-mop:method-generic-function object)
373 (sb-pcl::unparse-specializers
374 (sb-mop:method-generic-function object)
375 (sb-mop:method-specializers object))
376 (sb-mop:method-specializers object)))))
377 source))
378 #+sb-eval
379 (sb-eval:interpreted-function
380 (let ((source (translate-source-location
381 (sb-eval:interpreted-function-source-location object))))
382 source))
383 (function
384 (find-function-definition-source object))
385 ((or condition standard-object structure-object)
386 (find-definition-source (class-of object)))
388 (error "Don't know how to retrieve source location for a ~S"
389 (type-of object)))))
391 (defun find-function-definition-source (function)
392 (let* ((debug-info (function-debug-info function))
393 (debug-source (debug-info-source debug-info))
394 (debug-fun (debug-info-debug-function debug-info))
395 (tlf (if debug-fun (sb-c::compiled-debug-fun-tlf-number debug-fun))))
396 (make-definition-source
397 :pathname
398 ;; KLUDGE: at the moment, we don't record the correct toplevel
399 ;; form number for forms processed by EVAL (including EVAL-WHEN
400 ;; :COMPILE-TOPLEVEL). Until that's fixed, don't return a
401 ;; DEFINITION-SOURCE with a pathname. (When that's fixed, take
402 ;; out the (not (debug-source-form ...)) test.
403 (when (stringp (sb-c::debug-source-namestring debug-source))
404 (parse-namestring (sb-c::debug-source-namestring debug-source)))
405 :character-offset
406 (if tlf
407 (elt (sb-c::debug-source-start-positions debug-source) tlf))
408 ;; Unfortunately there is no proper source path available in the
409 ;; debug-source. FIXME: We could use sb-di:code-locations to get
410 ;; a full source path. -luke (12/Mar/2005)
411 :form-path (if tlf (list tlf))
412 :file-write-date (sb-c::debug-source-created debug-source)
413 :plist (sb-c::debug-source-plist debug-source))))
415 (defun translate-source-location (location)
416 (if location
417 (make-definition-source
418 :pathname (let ((n (sb-c:definition-source-location-namestring location)))
419 (when n
420 (parse-namestring n)))
421 :form-path
422 (let ((number (sb-c:definition-source-location-toplevel-form-number
423 location)))
424 (when number
425 (list number)))
426 :plist (sb-c:definition-source-location-plist location))
427 (make-definition-source)))
429 (sb-int:define-deprecated-function :final "1.2.10" function-arglist
430 function-lambda-list (function)
431 (function-lambda-list function))
433 (defun function-lambda-list (function)
434 "Describe the lambda list for the extended function designator FUNCTION.
435 Works for special-operators, macros, simple functions, interpreted functions,
436 and generic functions. Signals an error if FUNCTION is not a valid extended
437 function designator."
438 (cond ((valid-function-name-p function)
439 (function-lambda-list (or (and (symbolp function)
440 (macro-function function))
441 (fdefinition function))))
442 ((typep function 'generic-function)
443 (sb-pcl::generic-function-pretty-arglist function))
444 #+sb-eval
445 ((typep function 'sb-eval:interpreted-function)
446 (sb-eval:interpreted-function-debug-lambda-list function))
448 (sb-kernel:%simple-fun-arglist (sb-kernel:%fun-fun function)))))
450 (defun deftype-lambda-list (typespec-operator)
451 "Returns the lambda list of TYPESPEC-OPERATOR as first return
452 value, and a flag whether the arglist could be found as second
453 value."
454 (check-type typespec-operator symbol)
455 (case (sb-int:info :type :kind typespec-operator)
456 (:defined
457 (sb-int:info :type :lambda-list typespec-operator))
458 (:primitive
459 (let ((translator-fun (sb-int:info :type :translator typespec-operator)))
460 (if (functionp translator-fun)
461 (values (sb-kernel:%fun-lambda-list translator-fun) t)
462 ;; Some builtin types (e.g. STRING) do not have a
463 ;; translator, but they were actually defined via DEFTYPE
464 ;; in src/code/deftypes-for-target.lisp.
465 (sb-int:info :type :lambda-list typespec-operator))))
466 (t (values nil nil))))
468 (defun function-type (function-designator)
469 "Returns the ftype of FUNCTION-DESIGNATOR, or NIL."
470 (flet ((ftype-of (function-designator)
471 (sb-kernel:type-specifier
472 (sb-int:info :function :type function-designator))))
473 (etypecase function-designator
474 (symbol
475 (when (and (fboundp function-designator)
476 (not (macro-function function-designator))
477 (not (special-operator-p function-designator)))
478 (ftype-of function-designator)))
479 (cons
480 (when (and (sb-int:legal-fun-name-p function-designator)
481 (fboundp function-designator))
482 (ftype-of function-designator)))
483 (generic-function
484 (function-type (sb-pcl:generic-function-name function-designator)))
485 (function
486 ;; Give declared type in globaldb priority over derived type
487 ;; because it contains more accurate information e.g. for
488 ;; struct-accessors.
489 (let ((type (function-type (sb-kernel:%fun-name
490 (sb-impl::%fun-fun function-designator)))))
491 (if type
492 type
493 (sb-impl::%fun-type function-designator)))))))
495 ;;;; find callers/callees, liberated from Helmut Eller's code in SLIME
497 ;;; This interface is trmendously experimental.
499 ;;; For the moment I'm taking the view that FDEFN is an internal
500 ;;; object (one out of one CMUCL developer surveyed didn't know what
501 ;;; they were for), so these routines deal in FUNCTIONs
503 ;;; Find callers and callees by looking at the constant pool of
504 ;;; compiled code objects. We assume every fdefn object in the
505 ;;; constant pool corresponds to a call to that function. A better
506 ;;; strategy would be to use the disassembler to find actual
507 ;;; call-sites.
509 (defun find-function-callees (function)
510 "Return functions called by FUNCTION."
511 (declare (sb-kernel:simple-fun function))
512 (let ((callees '()))
513 (map-code-constants
514 (sb-kernel:fun-code-header function)
515 (lambda (obj)
516 (when (sb-kernel:fdefn-p obj)
517 (push (sb-kernel:fdefn-fun obj)
518 callees))))
519 callees))
522 (defun find-function-callers (function &optional (spaces '(:read-only :static
523 :dynamic)))
524 "Return functions which call FUNCTION, by searching SPACES for code objects"
525 (let ((referrers '()))
526 (map-caller-code-components
527 function
528 spaces
529 (lambda (code)
530 (let ((entry (sb-kernel:%code-entry-points code)))
531 (cond ((not entry)
532 (push (princ-to-string code) referrers))
534 (loop for e = entry then (sb-kernel::%simple-fun-next e)
535 while e
536 do (pushnew e referrers)))))))
537 referrers))
539 (declaim (inline map-code-constants)) ; FIXME: out-of-order
540 (defun map-code-constants (code fn)
541 "Call FN for each constant in CODE's constant pool."
542 (check-type code sb-kernel:code-component)
543 (loop for i from sb-vm:code-constants-offset below
544 (sb-kernel:get-header-data code)
545 do (funcall fn (sb-kernel:code-header-ref code i))))
547 (declaim (inline map-allocated-code-components))
548 (defun map-allocated-code-components (spaces fn)
549 "Call FN for each allocated code component in one of SPACES. FN
550 receives the object and its size as arguments. SPACES should be a
551 list of the symbols :dynamic, :static, or :read-only."
552 (dolist (space spaces)
553 (sb-vm::map-allocated-objects
554 (lambda (obj header size)
555 (when (= sb-vm:code-header-widetag header)
556 (funcall fn obj size)))
557 space)))
559 (declaim (inline map-caller-code-components)) ; FIXME: out-of-order
560 (defun map-caller-code-components (function spaces fn)
561 "Call FN for each code component with a fdefn for FUNCTION in its
562 constant pool."
563 (let ((function (coerce function 'function)))
564 (map-allocated-code-components
565 spaces
566 (lambda (obj size)
567 (declare (ignore size))
568 (map-code-constants
570 (lambda (constant)
571 (when (and (sb-kernel:fdefn-p constant)
572 (eq (sb-kernel:fdefn-fun constant)
573 function))
574 (funcall fn obj))))))))
576 ;;; XREF facility
578 (defun get-simple-fun (functoid)
579 (etypecase functoid
580 (sb-kernel::fdefn
581 (get-simple-fun (sb-vm::fdefn-fun functoid)))
582 ((or null sb-impl::funcallable-instance)
583 nil)
584 (function
585 (sb-kernel::%fun-fun functoid))))
587 ;; Call FUNCTION with two args, NAME and VALUE, for each value that is
588 ;; either the FDEFINITION or MACRO-FUNCTION of some global name.
590 (defun call-with-each-global-functoid (function)
591 (sb-c::call-with-each-globaldb-name
592 (lambda (name)
593 ;; In general it might be unsafe to call INFO with a NAME that is not
594 ;; valid for the kind of info being retrieved, as when the defaulting
595 ;; function tries to perform a sanity-check. But here it's safe.
596 (let ((functoid (or (sb-int:info :function :macro-function name)
597 (sb-int:info :function :definition name))))
598 (if functoid
599 (funcall function name functoid))))))
601 (defun collect-xref (kind-index wanted-name)
602 (let ((ret nil))
603 (call-with-each-global-functoid
604 (lambda (info-name value)
605 ;; Get a simple-fun for the definition, and an xref array
606 ;; from the table if available.
607 (let* ((simple-fun (get-simple-fun value))
608 (xrefs (when simple-fun
609 (sb-kernel:%simple-fun-xrefs simple-fun)))
610 (array (when xrefs
611 (aref xrefs kind-index))))
612 ;; Loop through the name/path xref entries in the table
613 (loop for i from 0 below (length array) by 2
614 for xref-name = (aref array i)
615 for xref-path = (aref array (1+ i))
616 do (when (equal xref-name wanted-name)
617 (let ((source-location
618 (find-function-definition-source simple-fun)))
619 ;; Use the more accurate source path from
620 ;; the xref entry.
621 (setf (definition-source-form-path source-location)
622 xref-path)
623 (push (cons info-name source-location)
624 ret)))))))
625 ret))
627 (defun who-calls (function-name)
628 "Use the xref facility to search for source locations where the
629 global function named FUNCTION-NAME is called. Returns a list of
630 function name, definition-source pairs."
631 (collect-xref #.(position :calls sb-c::*xref-kinds*) function-name))
633 (defun who-binds (symbol)
634 "Use the xref facility to search for source locations where the
635 special variable SYMBOL is rebound. Returns a list of function name,
636 definition-source pairs."
637 (collect-xref #.(position :binds sb-c::*xref-kinds*) symbol))
639 (defun who-references (symbol)
640 "Use the xref facility to search for source locations where the
641 special variable or constant SYMBOL is read. Returns a list of function
642 name, definition-source pairs."
643 (collect-xref #.(position :references sb-c::*xref-kinds*) symbol))
645 (defun who-sets (symbol)
646 "Use the xref facility to search for source locations where the
647 special variable SYMBOL is written to. Returns a list of function name,
648 definition-source pairs."
649 (collect-xref #.(position :sets sb-c::*xref-kinds*) symbol))
651 (defun who-macroexpands (macro-name)
652 "Use the xref facility to search for source locations where the
653 macro MACRO-NAME is expanded. Returns a list of function name,
654 definition-source pairs."
655 (collect-xref #.(position :macroexpands sb-c::*xref-kinds*) macro-name))
657 (defun who-specializes-directly (class-designator)
658 "Search for source locations of methods directly specializing on
659 CLASS-DESIGNATOR. Returns an alist of method name, definition-source
660 pairs.
662 A method matches the criterion either if it specializes on the same
663 class as CLASS-DESIGNATOR designates (this includes CLASS-EQ
664 specializers), or if it eql-specializes on an instance of the
665 designated class.
667 Experimental.
669 (let ((class (canonicalize-class-designator class-designator)))
670 (unless class
671 (return-from who-specializes-directly nil))
672 (let ((result (collect-specializing-methods
673 #'(lambda (specl)
674 ;; Does SPECL specialize on CLASS directly?
675 (typecase specl
676 (sb-pcl::class-eq-specializer
677 (eq (sb-pcl::specializer-object specl) class))
678 (sb-pcl::eql-specializer
679 (let ((obj (sb-mop:eql-specializer-object specl)))
680 (eq (class-of obj) class)))
681 ((not sb-pcl::standard-specializer)
682 nil)
684 (eq specl class)))))))
685 (map-into result #'(lambda (m)
686 (cons `(method ,(method-generic-function-name m))
687 (find-definition-source m)))
688 result))))
690 (defun who-specializes-generally (class-designator)
691 "Search for source locations of methods specializing on
692 CLASS-DESIGNATOR, or a subclass of it. Returns an alist of method
693 name, definition-source pairs.
695 A method matches the criterion either if it specializes on the
696 designated class itself or a subclass of it (this includes CLASS-EQ
697 specializers), or if it eql-specializes on an instance of the
698 designated class or a subclass of it.
700 Experimental.
702 (let ((class (canonicalize-class-designator class-designator)))
703 (unless class
704 (return-from who-specializes-generally nil))
705 (let ((result (collect-specializing-methods
706 #'(lambda (specl)
707 ;; Does SPECL specialize on CLASS or a subclass
708 ;; of it?
709 (typecase specl
710 (sb-pcl::class-eq-specializer
711 (subtypep (sb-pcl::specializer-object specl) class))
712 (sb-pcl::eql-specializer
713 (typep (sb-mop:eql-specializer-object specl) class))
714 ((not sb-pcl::standard-specializer)
715 nil)
717 (subtypep specl class)))))))
718 (map-into result #'(lambda (m)
719 (cons `(method ,(method-generic-function-name m))
720 (find-definition-source m)))
721 result))))
723 (defun canonicalize-class-designator (class-designator)
724 (typecase class-designator
725 (symbol (find-class class-designator nil))
726 (class class-designator)
727 (t nil)))
729 (defun method-generic-function-name (method)
730 (sb-mop:generic-function-name (sb-mop:method-generic-function method)))
732 (defun collect-specializing-methods (predicate)
733 (let ((result '()))
734 (sb-pcl::map-specializers
735 #'(lambda (specl)
736 (when (funcall predicate specl)
737 (let ((methods (sb-mop:specializer-direct-methods specl)))
738 (setf result (append methods result))))))
739 (delete-duplicates result)))
742 ;;;; ALLOCATION INTROSPECTION
744 (defun allocation-information (object)
745 #+sb-doc
746 "Returns information about the allocation of OBJECT. Primary return value
747 indicates the general type of allocation: :IMMEDIATE, :HEAP, :STACK,
748 or :FOREIGN.
750 Possible secondary return value provides additional information about the
751 allocation.
753 For :HEAP objects the secondary value is a plist:
755 :SPACE
756 Indicates the heap segment the object is allocated in.
758 :GENERATION
759 Is the current generation of the object: 0 for nursery, 6 for pseudo-static
760 generation loaded from core. (GENCGC and :SPACE :DYNAMIC only.)
762 :LARGE
763 Indicates a \"large\" object subject to non-copying
764 promotion. (GENCGC and :SPACE :DYNAMIC only.)
766 :BOXED
767 Indicates that the object is allocated in a boxed region. Unboxed
768 allocation is used for eg. specialized arrays after they have survived one
769 collection. (GENCGC and :SPACE :DYNAMIC only.)
771 :PINNED
772 Indicates that the page(s) on which the object resides are kept live due
773 to conservative references. Note that object may reside on a pinned page
774 even if :PINNED in NIL if the GC has not had the need to mark the the page
775 as pinned. (GENCGC and :SPACE :DYNAMIC only.)
777 :WRITE-PROTECTED
778 Indicates that the page on which the object starts is write-protected,
779 which indicates for :BOXED objects that it hasn't been written to since
780 the last GC of its generation. (GENCGC and :SPACE :DYNAMIC only.)
782 :PAGE
783 The index of the page the object resides on. (GENGC and :SPACE :DYNAMIC
784 only.)
786 For :STACK objects secondary value is the thread on whose stack the object is
787 allocated.
789 Expected use-cases include introspection to gain insight into allocation and
790 GC behaviour and restricting memoization to heap-allocated arguments.
792 Experimental: interface subject to change."
793 ;; FIXME: Would be nice to provide the size of the object as well, though
794 ;; maybe that should be a separate function, and something like MAP-PARTS
795 ;; for mapping over parts of arbitrary objects so users can get "deep sizes"
796 ;; as well if they want to.
798 ;; FIXME: For the memoization use-case possibly we should also provide a
799 ;; simpler HEAP-ALLOCATED-P, since that doesn't require disabling the GC
800 ;; scanning threads for negative answers? Similarly, STACK-ALLOCATED-P for
801 ;; checking if an object has been stack-allocated by a given thread for
802 ;; testing purposes might not come amiss.
803 (if (typep object '(or fixnum character
804 #.(if (= sb-vm:n-word-bits 64) 'single-float (values))))
805 (values :immediate nil)
806 (let ((plist
807 (sb-sys:without-gcing
808 ;; Disable GC so the object cannot move to another page while
809 ;; we have the address.
810 (let* ((addr (sb-kernel:get-lisp-obj-address object))
811 (space
812 (cond ((< sb-vm:read-only-space-start addr
813 (ash sb-vm:*read-only-space-free-pointer*
814 sb-vm:n-fixnum-tag-bits))
815 :read-only)
816 ((< sb-vm:static-space-start addr
817 (ash sb-vm:*static-space-free-pointer*
818 sb-vm:n-fixnum-tag-bits))
819 :static)
820 ((< (sb-kernel:current-dynamic-space-start) addr
821 (sb-sys:sap-int (sb-kernel:dynamic-space-free-pointer)))
822 :dynamic))))
823 (when space
824 #+gencgc
825 (if (eq :dynamic space)
826 (let ((index (sb-vm::find-page-index addr)))
827 (symbol-macrolet ((page (sb-alien:deref sb-vm::page-table index)))
828 (let ((flags (sb-alien:slot page 'sb-vm::flags)))
829 (list :space space
830 :generation (sb-alien:slot page 'sb-vm::gen)
831 :write-protected (logbitp 0 flags)
832 :boxed (logbitp 2 flags)
833 :pinned (logbitp 5 flags)
834 :large (logbitp 6 flags)
835 :page index))))
836 (list :space space))
837 #-gencgc
838 (list :space space))))))
839 (cond (plist
840 (values :heap plist))
842 (let ((sap (sb-sys:int-sap (sb-kernel:get-lisp-obj-address object))))
843 ;; FIXME: Check other stacks as well.
844 #+sb-thread
845 (dolist (thread (sb-thread:list-all-threads))
846 (let ((c-start (sb-di::descriptor-sap
847 (sb-thread::%symbol-value-in-thread
848 'sb-vm:*control-stack-start*
849 thread)))
850 (c-end (sb-di::descriptor-sap
851 (sb-thread::%symbol-value-in-thread
852 'sb-vm:*control-stack-end*
853 thread))))
854 (when (and c-start c-end)
855 (when (and (sb-sys:sap<= c-start sap)
856 (sb-sys:sap< sap c-end))
857 (return-from allocation-information
858 (values :stack thread))))))
859 #-sb-thread
860 (when (sb-vm:control-stack-pointer-valid-p sap nil)
861 (return-from allocation-information
862 (values :stack sb-thread::*current-thread*))))
863 :foreign)))))
865 (defun map-root (function object &key simple (ext t))
866 "Call FUNCTION with all non-immediate objects pointed to by OBJECT.
867 Returns OBJECT.
869 If SIMPLE is true (default is NIL), elides those pointers that are not
870 notionally part of certain built-in objects, but backpointers to a
871 conceptual parent: eg. elides the pointer from a SYMBOL to the
872 corresponding PACKAGE.
874 If EXT is true (default is T), includes some pointers that are not
875 actually contained in the object, but found in certain well-known
876 indirect containers: FDEFINITIONs, EQL specializers, classes, and
877 thread-local symbol values in other threads fall into this category.
879 NOTE: calling MAP-ROOT with a THREAD does not currently map over
880 conservative roots from the thread registers and interrupt contexts.
882 Experimental: interface subject to change."
883 (let ((fun (coerce function 'function))
884 (seen (sb-int:alloc-xset)))
885 (flet ((call (part)
886 (when (and (member (sb-kernel:lowtag-of part)
887 `(,sb-vm:instance-pointer-lowtag
888 ,sb-vm:list-pointer-lowtag
889 ,sb-vm:fun-pointer-lowtag
890 ,sb-vm:other-pointer-lowtag))
891 (not (sb-int:xset-member-p part seen)))
892 (sb-int:add-to-xset part seen)
893 (funcall fun part))))
894 (when ext
895 (let ((table sb-pcl::*eql-specializer-table*))
896 (call (sb-int:with-locked-system-table (table)
897 (gethash object table)))))
898 (etypecase object
899 ((or bignum float sb-sys:system-area-pointer fixnum))
900 (sb-ext:weak-pointer
901 (call (sb-ext:weak-pointer-value object)))
902 (cons
903 (call (car object))
904 (call (cdr object))
905 (when (and ext (ignore-errors (fboundp object)))
906 (call (fdefinition object))))
907 (ratio
908 (call (numerator object))
909 (call (denominator object)))
910 (complex
911 (call (realpart object))
912 (call (realpart object)))
913 (sb-vm::instance
914 (call (sb-kernel:%instance-layout object))
915 (sb-kernel:do-instance-tagged-slot (i object)
916 (call (sb-kernel:%instance-ref object i)))
917 #+sb-thread
918 (when (typep object 'sb-thread:thread)
919 (cond ((eq object sb-thread:*current-thread*)
920 (dolist (value (sb-thread::%thread-local-references))
921 (call value))
922 (sb-vm::map-stack-references #'call))
924 ;; KLUDGE: INTERRUPT-THREAD is Not Nice (tm), but
925 ;; the alternative would be stopping the world...
926 #+sb-thread
927 (let ((sem (sb-thread:make-semaphore))
928 (refs nil))
929 (handler-case
930 (progn
931 (sb-thread:interrupt-thread
932 object
933 (lambda ()
934 (setf refs (sb-thread::%thread-local-references))
935 (sb-vm::map-stack-references (lambda (x) (push x refs)))
936 (sb-thread:signal-semaphore sem)))
937 (sb-thread:wait-on-semaphore sem))
938 (sb-thread:interrupt-thread-error ()))
939 (mapc #'call refs))))))
940 (array
941 (if (simple-vector-p object)
942 (dotimes (i (length object))
943 (call (aref object i)))
944 (when (sb-kernel:array-header-p object)
945 (call (sb-kernel::%array-data-vector object))
946 (call (sb-kernel::%array-displaced-p object))
947 (unless simple
948 (call (sb-kernel::%array-displaced-from object))))))
949 (sb-kernel:code-component
950 (call (sb-kernel:%code-entry-points object))
951 (call (sb-kernel:%code-debug-info object))
952 (loop for i from sb-vm:code-constants-offset
953 below (sb-kernel:get-header-data object)
954 do (call (sb-kernel:code-header-ref object i))))
955 (sb-kernel:fdefn
956 (call (sb-kernel:fdefn-name object))
957 (call (sb-kernel:fdefn-fun object)))
958 (sb-kernel:simple-fun
959 (unless simple
960 (call (sb-kernel:%simple-fun-next object)))
961 (call (sb-kernel:fun-code-header object))
962 (call (sb-kernel:%simple-fun-name object))
963 (call (sb-kernel:%simple-fun-arglist object))
964 (call (sb-kernel:%simple-fun-type object))
965 (call (sb-kernel:%simple-fun-info object)))
966 (sb-kernel:closure
967 (call (sb-kernel:%closure-fun object))
968 (sb-kernel:do-closure-values (x object)
969 (call x)))
970 (sb-kernel:funcallable-instance
971 (call (sb-kernel:%funcallable-instance-function object))
972 (loop for i from 1 below (- (1+ (sb-kernel:get-closure-length object))
973 sb-vm::funcallable-instance-info-offset)
974 do (call (sb-kernel:%funcallable-instance-info object i))))
975 (symbol
976 (when ext
977 (dolist (thread (sb-thread:list-all-threads))
978 (call (sb-thread:symbol-value-in-thread object thread nil))))
979 (handler-case
980 ;; We don't have GLOBAL-BOUNDP, and there's no ERRORP arg.
981 (call (sb-ext:symbol-global-value object))
982 (unbound-variable ()))
983 ;; These first two are probably unnecessary.
984 ;; The functoid values, if present, are in SYMBOL-INFO
985 ;; which is traversed whether or not EXT was true.
986 ;; But should we traverse SYMBOL-INFO?
987 ;; I don't know what is expected of this interface.
988 (when (and ext (ignore-errors (fboundp object)))
989 (call (fdefinition object))
990 (call (macro-function object))
991 (let ((class (find-class object nil)))
992 (when class (call class))))
993 (call (symbol-plist object)) ; perhaps SB-KERNEL:SYMBOL-INFO instead?
994 (call (symbol-name object))
995 (unless simple
996 (call (symbol-package object))))
997 (sb-kernel::random-class
998 (case (sb-kernel:widetag-of object)
999 (#.sb-vm::value-cell-header-widetag
1000 (call (sb-kernel::value-cell-ref object)))
1002 (warn "~&MAP-ROOT: Unknown widetag ~S: ~S~%"
1003 (sb-kernel:widetag-of object) object)))))))
1004 object)