Add source locations for alien-types.
[sbcl.git] / contrib / sb-introspect / introspect.lisp
blob27cc94140379ddb7d83d279a86aaadaf95060186
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 ;;;; Utilities for code
105 (declaim (inline map-code-constants))
106 (defun map-code-constants (code fn)
107 "Call FN for each constant in CODE's constant pool."
108 (check-type code sb-kernel:code-component)
109 (loop for i from sb-vm:code-constants-offset below
110 (sb-kernel:get-header-data code)
111 do (funcall fn (sb-kernel:code-header-ref code i))))
113 (declaim (inline map-allocated-code-components))
114 (defun map-allocated-code-components (spaces fn)
115 "Call FN for each allocated code component in one of SPACES. FN
116 receives the object and its size as arguments. SPACES should be a
117 list of the symbols :dynamic, :static, or :read-only."
118 (dolist (space spaces)
119 (sb-vm::map-allocated-objects
120 (lambda (obj header size)
121 (when (= sb-vm:code-header-widetag header)
122 (funcall fn obj size)))
123 space)))
125 (declaim (inline map-caller-code-components))
126 (defun map-caller-code-components (function spaces fn)
127 "Call FN for each code component with a fdefn for FUNCTION in its
128 constant pool."
129 (let ((function (coerce function 'function)))
130 (map-allocated-code-components
131 spaces
132 (lambda (obj size)
133 (declare (ignore size))
134 (map-code-constants
136 (lambda (constant)
137 (when (and (sb-kernel:fdefn-p constant)
138 (eq (sb-kernel:fdefn-fun constant)
139 function))
140 (funcall fn obj))))))))
142 ;;;; Finding definitions
144 (defstruct definition-source
145 ;; Pathname of the source file that the definition was compiled from.
146 ;; This is null if the definition was not compiled from a file.
147 (pathname nil :type (or null pathname))
148 ;; Source-path of the definition within the file.
149 ;; This may be incomplete depending on the debug level at which the
150 ;; source was compiled.
151 (form-path '() :type list)
152 ;; Character offset of the top-level-form containing the definition.
153 ;; This corresponds to the first element of form-path.
154 (character-offset nil :type (or null integer))
155 ;; File-write-date of the source file when compiled.
156 ;; Null if not compiled from a file.
157 (file-write-date nil :type (or null integer))
158 ;; plist from WITH-COMPILATION-UNIT
159 (plist nil)
160 ;; Any extra metadata that the caller might be interested in. For
161 ;; example the specializers of the method whose definition-source this
162 ;; is.
163 (description nil :type list))
165 (defun find-definition-sources-by-name (name type)
166 "Returns a list of DEFINITION-SOURCEs for the objects of type TYPE
167 defined with name NAME. NAME may be a symbol or a extended function
168 name. Type can currently be one of the following:
170 (Public)
171 :CLASS
172 :COMPILER-MACRO
173 :CONDITION
174 :CONSTANT
175 :FUNCTION
176 :GENERIC-FUNCTION
177 :MACRO
178 :METHOD
179 :METHOD-COMBINATION
180 :PACKAGE
181 :SETF-EXPANDER
182 :STRUCTURE
183 :SYMBOL-MACRO
184 :TYPE
185 :ALIEN-TYPE
186 :VARIABLE
187 :DECLARATION
189 (Internal)
190 :OPTIMIZER
191 :SOURCE-TRANSFORM
192 :TRANSFORM
193 :VOP
194 :IR1-CONVERT
196 If an unsupported TYPE is requested, the function will return NIL.
198 (flet ((listify (x)
199 (if (listp x)
201 (list x)))
202 (get-class (name)
203 (and (symbolp name)
204 (find-class name nil)))
205 (real-fdefinition (name)
206 ;; for getting the real function object, even if the
207 ;; function is being profiled
208 (let ((profile-info (gethash name sb-profile::*profiled-fun-name->info*)))
209 (if profile-info
210 (sb-profile::profile-info-encapsulated-fun profile-info)
211 (fdefinition name)))))
212 (listify
213 (case type
214 ((:variable)
215 (when (and (symbolp name)
216 (member (sb-int:info :variable :kind name)
217 '(:global :special)))
218 (translate-source-location (sb-int:info :source-location type name))))
219 ((:constant)
220 (when (and (symbolp name)
221 (eq (sb-int:info :variable :kind name) :constant))
222 (translate-source-location (sb-int:info :source-location type name))))
223 ((:symbol-macro)
224 (when (and (symbolp name)
225 (eq (sb-int:info :variable :kind name) :macro))
226 (translate-source-location (sb-int:info :source-location type name))))
227 ((:macro)
228 (when (and (symbolp name)
229 (macro-function name))
230 (find-definition-source (macro-function name))))
231 ((:compiler-macro)
232 (when (compiler-macro-function name)
233 (find-definition-source (compiler-macro-function name))))
234 (:ir1-convert
235 (let ((converter (sb-int:info :function :ir1-convert name)))
236 (and converter
237 (find-definition-source converter))))
238 ((:function :generic-function)
239 (when (and (fboundp name)
240 (or (consp name)
241 (and
242 (not (macro-function name))
243 (not (special-operator-p name)))))
244 (let ((fun (real-fdefinition name)))
245 (when (eq (not (typep fun 'generic-function))
246 (not (eq type :generic-function)))
247 (find-definition-source fun)))))
248 ((:type)
249 ;; Source locations for types are saved separately when the expander
250 ;; is a closure without a good source-location.
251 (let ((loc (sb-int:info :type :source-location name)))
252 (if loc
253 (translate-source-location loc)
254 (let ((expander-fun (sb-int:info :type :expander name)))
255 (when expander-fun
256 (find-definition-source expander-fun))))))
257 ((:method)
258 (when (fboundp name)
259 (let ((fun (real-fdefinition name)))
260 (when (typep fun 'generic-function)
261 (loop for method in (sb-mop::generic-function-methods
262 fun)
263 for source = (find-definition-source method)
264 when source collect source)))))
265 ((:setf-expander)
266 (when (and (consp name)
267 (eq (car name) 'setf))
268 (setf name (cadr name)))
269 (let ((expander (or (sb-int:info :setf :inverse name)
270 (sb-int:info :setf :expander name))))
271 (when expander
272 (find-definition-source (if (symbolp expander)
273 (symbol-function expander)
274 expander)))))
275 ((:structure)
276 (let ((class (get-class name)))
277 (if class
278 (when (typep class 'sb-pcl::structure-class)
279 (find-definition-source class))
280 (when (sb-int:info :typed-structure :info name)
281 (translate-source-location
282 (sb-int:info :source-location :typed-structure name))))))
283 ((:condition :class)
284 (let ((class (get-class name)))
285 (when (and class
286 (not (typep class 'sb-pcl::structure-class)))
287 (when (eq (not (typep class 'sb-pcl::condition-class))
288 (not (eq type :condition)))
289 (find-definition-source class)))))
290 ((:method-combination)
291 (let ((combination-fun
292 (find-method #'sb-mop:find-method-combination
294 (list (find-class 'generic-function)
295 (list 'eql name)
297 nil)))
298 (when combination-fun
299 (find-definition-source combination-fun))))
300 ((:package)
301 (when (symbolp name)
302 (let ((package (find-package name)))
303 (when package
304 (find-definition-source package)))))
305 ;; TRANSFORM and OPTIMIZER handling from swank-sbcl
306 ((:transform)
307 (when (symbolp name)
308 (let ((fun-info (sb-int:info :function :info name)))
309 (when fun-info
310 (loop for xform in (sb-c::fun-info-transforms fun-info)
311 for source = (find-definition-source
312 (sb-c::transform-function xform))
313 for typespec = (sb-kernel:type-specifier
314 (sb-c::transform-type xform))
315 for note = (sb-c::transform-note xform)
316 do (setf (definition-source-description source)
317 (if (consp typespec)
318 (list (second typespec) note)
319 (list note)))
320 collect source)))))
321 ((:optimizer)
322 (let ((fun-info (and (symbolp name)
323 (sb-int:info :function :info name))))
324 (when fun-info
325 (let ((otypes '((sb-c:fun-info-derive-type . sb-c:derive-type)
326 (sb-c:fun-info-ltn-annotate . sb-c:ltn-annotate)
327 (sb-c:fun-info-optimizer . sb-c:optimizer)
328 (sb-c:fun-info-ir2-convert . sb-c:ir2-convert)
329 (sb-c::fun-info-stack-allocate-result
330 . sb-c::stack-allocate-result))))
331 (loop for (reader . name) in otypes
332 for fn = (funcall reader fun-info)
333 when fn collect
334 (let ((source (find-definition-source fn)))
335 (setf (definition-source-description source)
336 (list name))
337 source))))))
338 ((:vop :alien-type)
339 (let ((loc (sb-int:info :source-location type name)))
340 (and loc
341 (translate-source-location loc))))
342 ((:source-transform)
343 (let* ((transform-fun
344 (or (sb-int:info :function :source-transform name)
345 (and (typep name '(cons (eql setf) (cons symbol null)))
346 (sb-int:info :function :source-transform
347 (second name)))))
348 ;; A cons for the :source-transform is essentially the same
349 ;; info that was formerly in :structure-accessor.
350 (accessor (and (consp transform-fun) (cdr transform-fun))))
351 ;; Structure accessors have source transforms, but the
352 ;; returned locations will neither show the actual place
353 ;; where it's defined, nor is really interesting.
354 (when (and transform-fun
355 (not accessor))
356 (find-definition-source transform-fun))))
357 (:declaration
358 (let ((locations (sb-int:info :source-location :declaration name)))
359 (loop for (kind loc) on locations by #'cddr
360 when loc
361 collect (let ((loc (translate-source-location loc)))
362 (setf (definition-source-description loc) (list kind))
363 loc))))
365 nil)))))
367 (defun find-definition-source (object)
368 (typecase object
369 ((or sb-pcl::condition-class sb-pcl::structure-class)
370 (let ((classoid (sb-impl::find-classoid (class-name object))))
371 (when classoid
372 (let ((layout (sb-impl::classoid-layout classoid)))
373 (when layout
374 (translate-source-location
375 (sb-kernel::layout-source-location layout)))))))
376 (method-combination
377 (car
378 (find-definition-sources-by-name
379 (sb-pcl::method-combination-type-name object) :method-combination)))
380 (package
381 (translate-source-location (sb-impl::package-source-location object)))
382 (class
383 (translate-source-location (sb-pcl::definition-source object)))
384 ;; Use the PCL definition location information instead of the function
385 ;; debug-info for methods and generic functions. Sometimes the
386 ;; debug-info would point into PCL internals instead of the proper
387 ;; location.
388 (generic-function
389 (let ((source (translate-source-location
390 (sb-pcl::definition-source object))))
391 (when source
392 (setf (definition-source-description source)
393 (list (sb-mop:generic-function-lambda-list object))))
394 source))
395 (method
396 (let ((source (translate-source-location
397 (sb-pcl::definition-source object))))
398 (when source
399 (setf (definition-source-description source)
400 (append (method-qualifiers object)
401 (if (sb-mop:method-generic-function object)
402 (sb-pcl::unparse-specializers
403 (sb-mop:method-generic-function object)
404 (sb-mop:method-specializers object))
405 (sb-mop:method-specializers object)))))
406 source))
407 #+sb-eval
408 (sb-eval:interpreted-function
409 (let ((source (translate-source-location
410 (sb-eval:interpreted-function-source-location object))))
411 source))
412 (function
413 (find-function-definition-source object))
414 ((or condition standard-object structure-object)
415 (find-definition-source (class-of object)))
417 (error "Don't know how to retrieve source location for a ~S"
418 (type-of object)))))
420 (defun find-function-definition-source (function)
421 (let* ((debug-info (function-debug-info function))
422 (debug-source (debug-info-source debug-info))
423 (debug-fun (debug-info-debug-function debug-info))
424 (tlf (if debug-fun (sb-c::compiled-debug-fun-tlf-number debug-fun))))
425 (make-definition-source
426 :pathname
427 ;; KLUDGE: at the moment, we don't record the correct toplevel
428 ;; form number for forms processed by EVAL (including EVAL-WHEN
429 ;; :COMPILE-TOPLEVEL). Until that's fixed, don't return a
430 ;; DEFINITION-SOURCE with a pathname. (When that's fixed, take
431 ;; out the (not (debug-source-form ...)) test.
432 (when (stringp (sb-c::debug-source-namestring debug-source))
433 (parse-namestring (sb-c::debug-source-namestring debug-source)))
434 :character-offset
435 (if tlf
436 (elt (sb-c::debug-source-start-positions debug-source) tlf))
437 ;; Unfortunately there is no proper source path available in the
438 ;; debug-source. FIXME: We could use sb-di:code-locations to get
439 ;; a full source path. -luke (12/Mar/2005)
440 :form-path (if tlf (list tlf))
441 :file-write-date (sb-c::debug-source-created debug-source)
442 :plist (sb-c::debug-source-plist debug-source))))
444 (defun translate-source-location (location)
445 (if location
446 (make-definition-source
447 :pathname (let ((n (sb-c:definition-source-location-namestring location)))
448 (when n
449 (parse-namestring n)))
450 :form-path
451 (let ((number (sb-c:definition-source-location-toplevel-form-number
452 location)))
453 (when number
454 (list number)))
455 :plist (sb-c:definition-source-location-plist location))
456 (make-definition-source)))
458 (sb-int:define-deprecated-function :late "1.0.24.5" function-arglist function-lambda-list
459 (function)
460 (function-lambda-list function))
462 (defun function-lambda-list (function)
463 "Describe the lambda list for the extended function designator FUNCTION.
464 Works for special-operators, macros, simple functions, interpreted functions,
465 and generic functions. Signals an error if FUNCTION is not a valid extended
466 function designator."
467 (cond ((and (symbolp function) (special-operator-p function))
468 (function-lambda-list (sb-int:info :function :ir1-convert function)))
469 ((valid-function-name-p function)
470 (function-lambda-list (or (and (symbolp function)
471 (macro-function function))
472 (fdefinition function))))
473 ((typep function 'generic-function)
474 (sb-pcl::generic-function-pretty-arglist function))
475 #+sb-eval
476 ((typep function 'sb-eval:interpreted-function)
477 (sb-eval:interpreted-function-debug-lambda-list function))
479 (sb-kernel:%simple-fun-arglist (sb-kernel:%fun-fun function)))))
481 (defun deftype-lambda-list (typespec-operator)
482 "Returns the lambda list of TYPESPEC-OPERATOR as first return
483 value, and a flag whether the arglist could be found as second
484 value."
485 (check-type typespec-operator symbol)
486 ;; Don't return a lambda-list for combinators AND,OR,NOT.
487 (let ((f (and (sb-int:info :type :kind typespec-operator)
488 ;; globaldb prevents storing both of these
489 (or (sb-int:info :type :expander typespec-operator)
490 (sb-int:info :type :translator typespec-operator)))))
491 (if (functionp f)
492 (values (sb-kernel:%fun-lambda-list f) t)
493 (values nil nil))))
495 (defun function-type (function-designator)
496 "Returns the ftype of FUNCTION-DESIGNATOR, or NIL."
497 (flet ((ftype-of (function-designator)
498 (sb-kernel:type-specifier
499 (sb-int:info :function :type function-designator))))
500 (etypecase function-designator
501 (symbol
502 (when (and (fboundp function-designator)
503 (not (macro-function function-designator))
504 (not (special-operator-p function-designator)))
505 (ftype-of function-designator)))
506 (cons
507 (when (and (sb-int:legal-fun-name-p function-designator)
508 (fboundp function-designator))
509 (ftype-of function-designator)))
510 (generic-function
511 (function-type (sb-pcl:generic-function-name function-designator)))
512 (function
513 ;; Give declared type in globaldb priority over derived type
514 ;; because it contains more accurate information e.g. for
515 ;; struct-accessors.
516 (let ((type (function-type (sb-kernel:%fun-name
517 (sb-impl::%fun-fun function-designator)))))
518 (if type
519 type
520 (sb-impl::%fun-type function-designator)))))))
522 ;;;; find callers/callees, liberated from Helmut Eller's code in SLIME
524 ;;; This interface is tremendously experimental.
526 ;;; For the moment I'm taking the view that FDEFN is an internal
527 ;;; object (one out of one CMUCL developer surveyed didn't know what
528 ;;; they were for), so these routines deal in FUNCTIONs
530 ;;; Find callers and callees by looking at the constant pool of
531 ;;; compiled code objects. We assume every fdefn object in the
532 ;;; constant pool corresponds to a call to that function. A better
533 ;;; strategy would be to use the disassembler to find actual
534 ;;; call-sites.
536 (defun find-function-callees (function)
537 "Return functions called by FUNCTION."
538 (declare (sb-kernel:simple-fun function))
539 (let ((callees '()))
540 (map-code-constants
541 (sb-kernel:fun-code-header function)
542 (lambda (obj)
543 (when (sb-kernel:fdefn-p obj)
544 (push (sb-kernel:fdefn-fun obj)
545 callees))))
546 callees))
548 (defun find-function-callers (function &optional (spaces '(:read-only :static
549 :dynamic)))
550 "Return functions which call FUNCTION, by searching SPACES for code objects"
551 (let ((referrers '()))
552 (map-caller-code-components
553 function
554 spaces
555 (lambda (code)
556 (let ((entry (sb-kernel:%code-entry-points code)))
557 (cond ((not entry)
558 (push (princ-to-string code) referrers))
560 (loop for e = entry then (sb-kernel::%simple-fun-next e)
561 while e
562 do (pushnew e referrers)))))))
563 referrers))
565 ;;; XREF facility
567 (defun get-simple-fun (functoid)
568 (etypecase functoid
569 (sb-kernel::fdefn
570 (get-simple-fun (sb-vm::fdefn-fun functoid)))
571 ((or null sb-impl::funcallable-instance)
572 nil)
573 (function
574 (sb-kernel::%fun-fun functoid))))
576 ;; Call FUNCTION with two args, NAME and VALUE, for each value that is
577 ;; either the FDEFINITION or MACRO-FUNCTION of some global name.
579 (defun call-with-each-global-functoid (function)
580 (sb-c::call-with-each-globaldb-name
581 (lambda (name)
582 ;; In general it might be unsafe to call INFO with a NAME that is not
583 ;; valid for the kind of info being retrieved, as when the defaulting
584 ;; function tries to perform a sanity-check. But here it's safe.
585 (let ((functoid (or (sb-int:info :function :macro-function name)
586 (sb-int:info :function :definition name))))
587 (if functoid
588 (funcall function name functoid))))))
590 (defun collect-xref (kind-index wanted-name)
591 (let ((ret nil))
592 (call-with-each-global-functoid
593 (lambda (info-name value)
594 ;; Get a simple-fun for the definition, and an xref array
595 ;; from the table if available.
596 (let* ((simple-fun (get-simple-fun value))
597 (xrefs (when simple-fun
598 (sb-kernel:%simple-fun-xrefs simple-fun)))
599 (array (when xrefs
600 (aref xrefs kind-index))))
601 ;; Loop through the name/path xref entries in the table
602 (loop for i from 0 below (length array) by 2
603 for xref-name = (aref array i)
604 for xref-path = (aref array (1+ i))
605 do (when (equal xref-name wanted-name)
606 (let ((source-location
607 (find-function-definition-source simple-fun)))
608 ;; Use the more accurate source path from
609 ;; the xref entry.
610 (setf (definition-source-form-path source-location)
611 xref-path)
612 (push (cons info-name source-location)
613 ret)))))))
614 ret))
616 (defun who-calls (function-name)
617 "Use the xref facility to search for source locations where the
618 global function named FUNCTION-NAME is called. Returns a list of
619 function name, definition-source pairs."
620 (collect-xref #.(position :calls sb-c::*xref-kinds*) function-name))
622 (defun who-binds (symbol)
623 "Use the xref facility to search for source locations where the
624 special variable SYMBOL is rebound. Returns a list of function name,
625 definition-source pairs."
626 (collect-xref #.(position :binds sb-c::*xref-kinds*) symbol))
628 (defun who-references (symbol)
629 "Use the xref facility to search for source locations where the
630 special variable or constant SYMBOL is read. Returns a list of function
631 name, definition-source pairs."
632 (collect-xref #.(position :references sb-c::*xref-kinds*) symbol))
634 (defun who-sets (symbol)
635 "Use the xref facility to search for source locations where the
636 special variable SYMBOL is written to. Returns a list of function name,
637 definition-source pairs."
638 (collect-xref #.(position :sets sb-c::*xref-kinds*) symbol))
640 (defun who-macroexpands (macro-name)
641 "Use the xref facility to search for source locations where the
642 macro MACRO-NAME is expanded. Returns a list of function name,
643 definition-source pairs."
644 (collect-xref #.(position :macroexpands sb-c::*xref-kinds*) macro-name))
646 (defun who-specializes-directly (class-designator)
647 "Search for source locations of methods directly specializing on
648 CLASS-DESIGNATOR. Returns an alist of method name, definition-source
649 pairs.
651 A method matches the criterion either if it specializes on the same
652 class as CLASS-DESIGNATOR designates (this includes CLASS-EQ
653 specializers), or if it eql-specializes on an instance of the
654 designated class.
656 Experimental.
658 (let ((class (canonicalize-class-designator class-designator)))
659 (unless class
660 (return-from who-specializes-directly nil))
661 (let ((result (collect-specializing-methods
662 #'(lambda (specl)
663 ;; Does SPECL specialize on CLASS directly?
664 (typecase specl
665 (sb-pcl::class-eq-specializer
666 (eq (sb-pcl::specializer-object specl) class))
667 (sb-pcl::eql-specializer
668 (let ((obj (sb-mop:eql-specializer-object specl)))
669 (eq (class-of obj) class)))
670 ((not sb-pcl::standard-specializer)
671 nil)
673 (eq specl class)))))))
674 (map-into result #'(lambda (m)
675 (cons `(method ,(method-generic-function-name m))
676 (find-definition-source m)))
677 result))))
679 (defun who-specializes-generally (class-designator)
680 "Search for source locations of methods specializing on
681 CLASS-DESIGNATOR, or a subclass of it. Returns an alist of method
682 name, definition-source pairs.
684 A method matches the criterion either if it specializes on the
685 designated class itself or a subclass of it (this includes CLASS-EQ
686 specializers), or if it eql-specializes on an instance of the
687 designated class or a subclass of it.
689 Experimental.
691 (let ((class (canonicalize-class-designator class-designator)))
692 (unless class
693 (return-from who-specializes-generally nil))
694 (let ((result (collect-specializing-methods
695 #'(lambda (specl)
696 ;; Does SPECL specialize on CLASS or a subclass
697 ;; of it?
698 (typecase specl
699 (sb-pcl::class-eq-specializer
700 (subtypep (sb-pcl::specializer-object specl) class))
701 (sb-pcl::eql-specializer
702 (typep (sb-mop:eql-specializer-object specl) class))
703 ((not sb-pcl::standard-specializer)
704 nil)
706 (subtypep specl class)))))))
707 (map-into result #'(lambda (m)
708 (cons `(method ,(method-generic-function-name m))
709 (find-definition-source m)))
710 result))))
712 (defun canonicalize-class-designator (class-designator)
713 (typecase class-designator
714 (symbol (find-class class-designator nil))
715 (class class-designator)
716 (t nil)))
718 (defun method-generic-function-name (method)
719 (sb-mop:generic-function-name (sb-mop:method-generic-function method)))
721 (defun collect-specializing-methods (predicate)
722 (let ((result '()))
723 (sb-pcl::map-specializers
724 #'(lambda (specl)
725 (when (funcall predicate specl)
726 (let ((methods (sb-mop:specializer-direct-methods specl)))
727 (setf result (append methods result))))))
728 (delete-duplicates result)))
731 ;;;; ALLOCATION INTROSPECTION
733 (defun allocation-information (object)
734 #+sb-doc
735 "Returns information about the allocation of OBJECT. Primary return value
736 indicates the general type of allocation: :IMMEDIATE, :HEAP, :STACK,
737 or :FOREIGN.
739 Possible secondary return value provides additional information about the
740 allocation.
742 For :HEAP objects the secondary value is a plist:
744 :SPACE
745 Indicates the heap segment the object is allocated in.
747 :GENERATION
748 Is the current generation of the object: 0 for nursery, 6 for pseudo-static
749 generation loaded from core. (GENCGC and :SPACE :DYNAMIC only.)
751 :LARGE
752 Indicates a \"large\" object subject to non-copying
753 promotion. (GENCGC and :SPACE :DYNAMIC only.)
755 :BOXED
756 Indicates that the object is allocated in a boxed region. Unboxed
757 allocation is used for eg. specialized arrays after they have survived one
758 collection. (GENCGC and :SPACE :DYNAMIC only.)
760 :PINNED
761 Indicates that the page(s) on which the object resides are kept live due
762 to conservative references. Note that object may reside on a pinned page
763 even if :PINNED in NIL if the GC has not had the need to mark the the page
764 as pinned. (GENCGC and :SPACE :DYNAMIC only.)
766 :WRITE-PROTECTED
767 Indicates that the page on which the object starts is write-protected,
768 which indicates for :BOXED objects that it hasn't been written to since
769 the last GC of its generation. (GENCGC and :SPACE :DYNAMIC only.)
771 :PAGE
772 The index of the page the object resides on. (GENGC and :SPACE :DYNAMIC
773 only.)
775 For :STACK objects secondary value is the thread on whose stack the object is
776 allocated.
778 Expected use-cases include introspection to gain insight into allocation and
779 GC behaviour and restricting memoization to heap-allocated arguments.
781 Experimental: interface subject to change."
782 ;; FIXME: Would be nice to provide the size of the object as well, though
783 ;; maybe that should be a separate function, and something like MAP-PARTS
784 ;; for mapping over parts of arbitrary objects so users can get "deep sizes"
785 ;; as well if they want to.
787 ;; FIXME: For the memoization use-case possibly we should also provide a
788 ;; simpler HEAP-ALLOCATED-P, since that doesn't require disabling the GC
789 ;; scanning threads for negative answers? Similarly, STACK-ALLOCATED-P for
790 ;; checking if an object has been stack-allocated by a given thread for
791 ;; testing purposes might not come amiss.
792 (if (typep object '(or fixnum character
793 #.(if (= sb-vm:n-word-bits 64) 'single-float (values))))
794 (values :immediate nil)
795 (let ((plist
796 (sb-sys:without-gcing
797 ;; Disable GC so the object cannot move to another page while
798 ;; we have the address.
799 (let* ((addr (sb-kernel:get-lisp-obj-address object))
800 (space
801 (cond ((< sb-vm:read-only-space-start addr
802 (ash sb-vm:*read-only-space-free-pointer*
803 sb-vm:n-fixnum-tag-bits))
804 :read-only)
805 ((< sb-vm:static-space-start addr
806 (ash sb-vm:*static-space-free-pointer*
807 sb-vm:n-fixnum-tag-bits))
808 :static)
809 ((< (sb-kernel:current-dynamic-space-start) addr
810 (sb-sys:sap-int (sb-kernel:dynamic-space-free-pointer)))
811 :dynamic))))
812 (when space
813 #+gencgc
814 (if (eq :dynamic space)
815 (let ((index (sb-vm::find-page-index addr)))
816 (symbol-macrolet ((page (sb-alien:deref sb-vm::page-table index)))
817 (let ((flags (sb-alien:slot page 'sb-vm::flags)))
818 (list :space space
819 :generation (sb-alien:slot page 'sb-vm::gen)
820 :write-protected (logbitp 0 flags)
821 :boxed (logbitp 2 flags)
822 :pinned (logbitp 5 flags)
823 :large (logbitp 6 flags)
824 :page index))))
825 (list :space space))
826 #-gencgc
827 (list :space space))))))
828 (cond (plist
829 (values :heap plist))
831 (let ((sap (sb-sys:int-sap (sb-kernel:get-lisp-obj-address object))))
832 ;; FIXME: Check other stacks as well.
833 #+sb-thread
834 (dolist (thread (sb-thread:list-all-threads))
835 (let ((c-start (sb-di::descriptor-sap
836 (sb-thread::%symbol-value-in-thread
837 'sb-vm:*control-stack-start*
838 thread)))
839 (c-end (sb-di::descriptor-sap
840 (sb-thread::%symbol-value-in-thread
841 'sb-vm:*control-stack-end*
842 thread))))
843 (when (and c-start c-end)
844 (when (and (sb-sys:sap<= c-start sap)
845 (sb-sys:sap< sap c-end))
846 (return-from allocation-information
847 (values :stack thread))))))
848 #-sb-thread
849 (when (sb-vm:control-stack-pointer-valid-p sap nil)
850 (return-from allocation-information
851 (values :stack sb-thread::*current-thread*))))
852 :foreign)))))
854 (defun map-root (function object &key simple (ext t))
855 "Call FUNCTION with all non-immediate objects pointed to by OBJECT.
856 Returns OBJECT.
858 If SIMPLE is true (default is NIL), elides those pointers that are not
859 notionally part of certain built-in objects, but backpointers to a
860 conceptual parent: eg. elides the pointer from a SYMBOL to the
861 corresponding PACKAGE.
863 If EXT is true (default is T), includes some pointers that are not
864 actually contained in the object, but found in certain well-known
865 indirect containers: FDEFINITIONs, EQL specializers, classes, and
866 thread-local symbol values in other threads fall into this category.
868 NOTE: calling MAP-ROOT with a THREAD does not currently map over
869 conservative roots from the thread registers and interrupt contexts.
871 Experimental: interface subject to change."
872 (let ((fun (coerce function 'function))
873 (seen (sb-int:alloc-xset)))
874 (flet ((call (part)
875 (when (and (member (sb-kernel:lowtag-of part)
876 `(,sb-vm:instance-pointer-lowtag
877 ,sb-vm:list-pointer-lowtag
878 ,sb-vm:fun-pointer-lowtag
879 ,sb-vm:other-pointer-lowtag))
880 (not (sb-int:xset-member-p part seen)))
881 (sb-int:add-to-xset part seen)
882 (funcall fun part))))
883 (when ext
884 (let ((table sb-pcl::*eql-specializer-table*))
885 (call (sb-int:with-locked-system-table (table)
886 (gethash object table)))))
887 (etypecase object
888 ((or bignum float sb-sys:system-area-pointer fixnum))
889 (sb-ext:weak-pointer
890 (call (sb-ext:weak-pointer-value object)))
891 (cons
892 (call (car object))
893 (call (cdr object))
894 (when (and ext (ignore-errors (fboundp object)))
895 (call (fdefinition object))))
896 (ratio
897 (call (numerator object))
898 (call (denominator object)))
899 (complex
900 (call (realpart object))
901 (call (realpart object)))
902 (sb-vm::instance
903 (call (sb-kernel:%instance-layout object))
904 (sb-kernel:do-instance-tagged-slot (i object)
905 (call (sb-kernel:%instance-ref object i)))
906 #+sb-thread
907 (when (typep object 'sb-thread:thread)
908 (cond ((eq object sb-thread:*current-thread*)
909 (dolist (value (sb-thread::%thread-local-references))
910 (call value))
911 (sb-vm::map-stack-references #'call))
913 ;; KLUDGE: INTERRUPT-THREAD is Not Nice (tm), but
914 ;; the alternative would be stopping the world...
915 #+sb-thread
916 (let ((sem (sb-thread:make-semaphore))
917 (refs nil))
918 (handler-case
919 (progn
920 (sb-thread:interrupt-thread
921 object
922 (lambda ()
923 (setf refs (sb-thread::%thread-local-references))
924 (sb-vm::map-stack-references (lambda (x) (push x refs)))
925 (sb-thread:signal-semaphore sem)))
926 (sb-thread:wait-on-semaphore sem))
927 (sb-thread:interrupt-thread-error ()))
928 (mapc #'call refs))))))
929 (array
930 (if (simple-vector-p object)
931 (dotimes (i (length object))
932 (call (aref object i)))
933 (when (sb-kernel:array-header-p object)
934 (call (sb-kernel::%array-data-vector object))
935 (call (sb-kernel::%array-displaced-p object))
936 (unless simple
937 (call (sb-kernel::%array-displaced-from object))))))
938 (sb-kernel:code-component
939 (call (sb-kernel:%code-entry-points object))
940 (call (sb-kernel:%code-debug-info object))
941 (loop for i from sb-vm:code-constants-offset
942 below (sb-kernel:get-header-data object)
943 do (call (sb-kernel:code-header-ref object i))))
944 (sb-kernel:fdefn
945 (call (sb-kernel:fdefn-name object))
946 (call (sb-kernel:fdefn-fun object)))
947 (sb-kernel:simple-fun
948 (unless simple
949 (call (sb-kernel:%simple-fun-next object)))
950 (call (sb-kernel:fun-code-header object))
951 (call (sb-kernel:%simple-fun-name object))
952 (call (sb-kernel:%simple-fun-arglist object))
953 (call (sb-kernel:%simple-fun-type object))
954 (call (sb-kernel:%simple-fun-info object)))
955 (sb-kernel:closure
956 (call (sb-kernel:%closure-fun object))
957 (sb-kernel:do-closure-values (x object)
958 (call x)))
959 (sb-kernel:funcallable-instance
960 (call (sb-kernel:%funcallable-instance-function object))
961 (loop for i from 1 below (- (1+ (sb-kernel:get-closure-length object))
962 sb-vm::funcallable-instance-info-offset)
963 do (call (sb-kernel:%funcallable-instance-info object i))))
964 (symbol
965 (when ext
966 (dolist (thread (sb-thread:list-all-threads))
967 (call (sb-thread:symbol-value-in-thread object thread nil))))
968 (handler-case
969 ;; We don't have GLOBAL-BOUNDP, and there's no ERRORP arg.
970 (call (sb-ext:symbol-global-value object))
971 (unbound-variable ()))
972 ;; These first two are probably unnecessary.
973 ;; The functoid values, if present, are in SYMBOL-INFO
974 ;; which is traversed whether or not EXT was true.
975 ;; But should we traverse SYMBOL-INFO?
976 ;; I don't know what is expected of this interface.
977 (when (and ext (ignore-errors (fboundp object)))
978 (call (fdefinition object))
979 (call (macro-function object))
980 (let ((class (find-class object nil)))
981 (when class (call class))))
982 (call (symbol-plist object)) ; perhaps SB-KERNEL:SYMBOL-INFO instead?
983 (call (symbol-name object))
984 (unless simple
985 (call (symbol-package object))))
986 (sb-kernel::random-class
987 (case (sb-kernel:widetag-of object)
988 (#.sb-vm::value-cell-header-widetag
989 (call (sb-kernel::value-cell-ref object)))
991 (warn "~&MAP-ROOT: Unknown widetag ~S: ~S~%"
992 (sb-kernel:widetag-of object) object)))))))
993 object)