1 ;;; introspection library
3 ;;;; This software is part of the SBCL system. See the README file for
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.
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?
29 (defpackage :sb-introspect
30 (:use
"CL" "SB-KERNEL" "SB-INT")
31 (:import-from
"SB-VM" "PRIMITIVE-OBJECT-SIZE")
32 (:shadow
"VALID-FUNCTION-NAME-P")
33 (:export
"ALLOCATION-INFORMATION"
35 "FUNCTION-LAMBDA-LIST"
37 "METHOD-COMBINATION-LAMBDA-LIST"
39 "VALID-FUNCTION-NAME-P"
40 "FIND-DEFINITION-SOURCE"
41 "FIND-DEFINITION-SOURCES-BY-NAME"
43 "DEFINITION-SOURCE-PATHNAME"
44 "DEFINITION-SOURCE-FORM-PATH"
45 "DEFINITION-SOURCE-FORM-NUMBER"
46 "DEFINITION-SOURCE-CHARACTER-OFFSET"
47 "DEFINITION-SOURCE-FILE-WRITE-DATE"
48 "DEFINITION-SOURCE-PLIST"
49 "FIND-FUNCTION-CALLEES"
50 "FIND-FUNCTION-CALLERS"
57 "WHO-SPECIALIZES-DIRECTLY"
58 "WHO-SPECIALIZES-GENERALLY"))
60 (in-package :sb-introspect
)
61 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
62 (setf (system-package-p *package
*) t
))
64 ;;;; Internal interface for SBCL debug info
66 ;;; Here are some tutorial-style type definitions to help understand
67 ;;; the internal SBCL debugging data structures we're using. The
68 ;;; commentary is based on CMUCL's debug internals manual.
70 (deftype debug-info
()
71 "Structure containing all the debug information related to a function.
72 Function objects reference debug-infos which in turn reference
73 debug-sources and so on."
74 'sb-c
::compiled-debug-info
)
76 (deftype debug-source
()
77 "Debug sources describe where to find source code.
78 For example, the debug source for a function compiled from a file will
79 include the pathname of the file and the position of the definition."
82 (declaim (ftype (sfunction (function) debug-info
) function-debug-info
))
83 (defun function-debug-info (function)
84 (let* ((function-object (%fun-fun function
))
85 (function-header (fun-code-header function-object
)))
86 (%code-debug-info function-header
)))
88 (declaim (ftype (sfunction (function) debug-source
) function-debug-source
))
89 (defun function-debug-source (function)
90 (debug-info-source (function-debug-info function
)))
92 (declaim (ftype (sfunction (debug-info) debug-source
) debug-info-source
))
93 (defun debug-info-source (debug-info)
94 (sb-c::debug-info-source debug-info
))
96 (defun valid-function-name-p (name)
97 "True if NAME denotes a valid function name, ie. one that can be passed to
99 (and (sb-int:valid-function-name-p name
) t
))
101 ;;;; Utilities for code
103 (declaim (inline map-code-constants
))
104 (defun map-code-constants (code fn
)
105 "Call FN for each constant in CODE's constant pool."
106 (check-type code code-component
)
107 (loop for i from sb-vm
:code-constants-offset below
(code-header-words code
)
108 do
(funcall fn
(code-header-ref code i
))))
110 (declaim (inline map-allocated-code-components
))
111 (defun map-allocated-code-components (spaces fn
)
112 "Call FN for each allocated code component in one of SPACES. FN
113 receives the object and its size as arguments. SPACES should be a
114 list of the symbols :dynamic, :static, :read-only, or :immobile on
116 (apply #'sb-vm
:map-allocated-objects
117 (lambda (obj header size
)
118 (when (= sb-vm
:code-header-widetag header
)
119 (funcall fn obj size
)))
122 (declaim (inline map-caller-code-components
))
123 (defun map-caller-code-components (function spaces fn
)
124 "Call FN for each code component with a fdefn for FUNCTION in its
126 (let ((function (coerce function
'function
)))
127 (map-allocated-code-components
130 (declare (ignore size
))
134 (when (and (fdefn-p constant
)
135 (eq (fdefn-fun constant
) function
))
136 (funcall fn obj
))))))))
138 ;;;; Finding definitions
140 (defstruct definition-source
141 ;; Pathname of the source file that the definition was compiled from.
142 ;; This is null if the definition was not compiled from a file.
143 (pathname nil
:type
(or null pathname
))
144 ;; Source-path of the definition within the file.
145 ;; This may be incomplete depending on the debug level at which the
146 ;; source was compiled.
147 (form-path '() :type list
)
148 ;; Depth first number of the form.
149 ;; FORM-PATH above usually contains just the top-level form number,
150 ;; ideally the proper form path could be dervied from the
151 ;; form-number and the tlf-number, but it's a bit complicated and
152 ;; Slime already knows how to deal with form numbers, so delegate
153 ;; that job to Slime.
154 (form-number nil
:type
(or null unsigned-byte
))
155 ;; Character offset of the top-level-form containing the definition.
156 ;; This corresponds to the first element of form-path.
157 (character-offset nil
:type
(or null unsigned-byte
))
158 ;; File-write-date of the source file when compiled.
159 ;; Null if not compiled from a file.
160 (file-write-date nil
:type
(or null unsigned-byte
))
161 ;; plist from WITH-COMPILATION-UNIT
163 ;; Any extra metadata that the caller might be interested in. For
164 ;; example the specializers of the method whose definition-source this
166 (description nil
:type list
))
168 (defun vops-translating-fun (name)
169 (let ((fun-info (info :function
:info name
)))
171 (sb-c::fun-info-templates fun-info
))))
173 (defun find-vop-source (name)
174 (let* ((vop (gethash name sb-c
::*backend-parsed-vops
*))
175 (translating (vops-translating-fun name
))
177 (cons vop
(remove vop translating
))
179 (loop for vop in vops
180 for vop-parse
= (if (typep vop
'sb-c
::vop-parse
)
182 (gethash (sb-c::vop-info-name vop
)
183 sb-c
::*backend-parsed-vops
*))
184 for name
= (and vop-parse
185 (sb-c::vop-parse-name vop-parse
))
186 for loc
= (and vop-parse
187 (sb-c::vop-parse-source-location vop-parse
))
189 collect
(let ((source (translate-source-location loc
)))
190 (setf (definition-source-description source
)
191 (if (sb-c::vop-parse-note vop-parse
)
192 (list name
(sb-c::vop-parse-note vop-parse
))
196 (defun find-definition-sources-by-name (name type
)
197 "Returns a list of DEFINITION-SOURCEs for the objects of type TYPE
198 defined with name NAME. NAME may be a symbol or a extended function
199 name. Type can currently be one of the following:
227 If an unsupported TYPE is requested, the function will return NIL.
229 (flet ((get-class (name)
231 (find-class name nil
)))
232 (real-fdefinition (name)
233 ;; for getting the real function object, even if the
234 ;; function is being profiled
235 (let ((profile-info (gethash name sb-profile
::*profiled-fun-name-
>info
*)))
237 (sb-profile::profile-info-encapsulated-fun profile-info
)
238 (fdefinition name
)))))
242 (when (and (symbolp name
)
243 (member (info :variable
:kind name
)
244 '(:global
:special
:alien
)))
245 (translate-source-location (info :source-location type name
))))
247 (when (and (symbolp name
)
248 (eq (info :variable
:kind name
) :constant
))
249 (translate-source-location (info :source-location type name
))))
251 (when (and (symbolp name
)
252 (eq (info :variable
:kind name
) :macro
))
253 (translate-source-location (info :source-location type name
))))
255 (when (and (symbolp name
)
256 (macro-function name
))
257 (find-definition-source (macro-function name
))))
259 (when (compiler-macro-function name
)
260 (find-definition-source (compiler-macro-function name
))))
262 (let ((converter (info :function
:ir1-convert name
)))
264 (find-definition-source converter
))))
265 ((:function
:generic-function
)
266 (when (and (fboundp name
)
269 (not (macro-function name
))
270 (not (special-operator-p name
)))))
271 (let ((fun (real-fdefinition name
)))
272 (when (eq (not (typep fun
'generic-function
))
273 (not (eq type
:generic-function
)))
274 (find-definition-source fun
)))))
276 ;; Source locations for types are saved separately when the expander
277 ;; is a closure without a good source-location.
278 (let ((loc (info :type
:source-location name
)))
280 (translate-source-location loc
)
281 (let ((expander-fun (info :type
:expander name
)))
282 (when (functionp expander-fun
)
283 (find-definition-source expander-fun
))))))
286 (let ((fun (real-fdefinition name
)))
287 (when (typep fun
'generic-function
)
288 (loop for method in
(sb-mop::generic-function-methods
290 for source
= (find-definition-source method
)
291 when source collect source
)))))
293 (when (and (consp name
)
294 (eq (car name
) 'setf
))
295 (setf name
(cadr name
)))
296 (let ((expander (info :setf
:expander name
)))
297 (cond ((typep expander
'(cons symbol
))
298 (translate-source-location (cddr expander
)))
300 (find-definition-source
301 (if (listp expander
) (cdr expander
) expander
))))))
303 (let ((class (get-class name
)))
305 (when (typep class
'sb-pcl
::structure-class
)
306 (find-definition-source class
))
307 (when (info :typed-structure
:info name
)
308 (translate-source-location
309 (info :source-location
:typed-structure name
))))))
311 (let ((class (get-class name
)))
313 (not (typep class
'sb-pcl
::structure-class
)))
314 (when (eq (not (typep class
'sb-pcl
::condition-class
))
315 (not (eq type
:condition
)))
316 (find-definition-source class
)))))
317 ((:method-combination
)
318 (let ((info (gethash name sb-pcl
::**method-combinations
**)))
320 (translate-source-location
321 (sb-pcl::method-combination-info-source-location info
)))))
324 (let ((package (find-package name
)))
326 (find-definition-source package
)))))
327 ;; TRANSFORM and OPTIMIZER handling from swank-sbcl
329 (let ((fun-info (info :function
:info name
)))
331 (loop for xform in
(sb-c::fun-info-transforms fun-info
)
332 for source
= (find-definition-source
333 (sb-c::transform-function xform
))
334 for typespec
= (type-specifier
335 (sb-c::transform-type xform
))
336 for note
= (sb-c::transform-note xform
)
337 do
(setf (definition-source-description source
)
339 (list (second typespec
) note
)
343 (let ((fun-info (and (symbolp name
)
344 (info :function
:info name
))))
346 (let ((otypes '((sb-c:fun-info-derive-type . sb-c
:derive-type
)
347 (sb-c:fun-info-ltn-annotate . sb-c
:ltn-annotate
)
348 (sb-c:fun-info-optimizer . sb-c
:optimizer
)
349 (sb-c:fun-info-ir2-convert . sb-c
:ir2-convert
)
350 (sb-c::fun-info-ir2-hook . sb-c
::ir2-hook
)
351 (sb-c::fun-info-stack-allocate-result
352 . sb-c
::stack-allocate-result
)
353 (sb-c::fun-info-constraint-propagate
354 . sb-c
::constraint-propagate
)
355 (sb-c::fun-info-constraint-propagate-if
356 . sb-c
::constraint-propagate-if
)
357 (sb-c::fun-info-call-type-deriver
358 . sb-c
::call-type-deriver
))))
359 (loop for
(reader . name
) in otypes
360 for fn
= (funcall reader fun-info
)
362 (let ((source (find-definition-source fn
)))
363 (setf (definition-source-description source
)
367 (find-vop-source name
))
369 (let ((loc (info :source-location type name
)))
371 (translate-source-location loc
))))
373 (let* ((transform-fun
374 (or (info :function
:source-transform name
)
375 (and (typep name
'(cons (eql setf
) (cons symbol null
)))
376 (info :function
:source-transform
378 ;; A cons for the :source-transform is essentially the same
379 ;; info that was formerly in :structure-accessor.
380 (accessor (and (consp transform-fun
) (cdr transform-fun
))))
381 ;; Structure accessors have source transforms, but the
382 ;; returned locations will neither show the actual place
383 ;; where it's defined, nor is really interesting.
384 (when (and transform-fun
386 (find-definition-source transform-fun
))))
388 (let ((locations (info :source-location
:declaration name
)))
389 (loop for
(kind loc
) on locations by
#'cddr
391 collect
(let ((loc (translate-source-location loc
)))
392 (setf (definition-source-description loc
)
393 ;; Copy list to ensure that user code
394 ;; cannot mutate the original.
395 (copy-list (ensure-list kind
)))
400 (defun find-definition-source (object)
402 ((or sb-pcl
::condition-class sb-pcl
::structure-class
)
403 (let ((classoid (sb-pcl::class-classoid object
)))
405 (translate-source-location
406 (sb-kernel::classoid-source-location classoid
)))))
409 (find-definition-sources-by-name
410 (sb-pcl::method-combination-type-name object
) :method-combination
)))
412 (translate-source-location (sb-impl::package-source-location object
)))
413 ((or class sb-mop
:slot-definition
)
414 (translate-source-location (sb-pcl::definition-source object
)))
415 ;; Use the PCL definition location information instead of the function
416 ;; debug-info for methods and generic functions. Sometimes the
417 ;; debug-info would point into PCL internals instead of the proper
420 (let ((source (translate-source-location
421 (sb-pcl::definition-source object
))))
423 (setf (definition-source-description source
)
424 (list (sb-mop:generic-function-lambda-list object
))))
427 (let ((source (translate-source-location
428 (sb-pcl::definition-source object
))))
430 (setf (definition-source-description source
)
431 (append (method-qualifiers object
)
432 (if (sb-mop:method-generic-function object
)
433 (sb-pcl::unparse-specializers
434 (sb-mop:method-generic-function object
)
435 (sb-mop:method-specializers object
))
436 (sb-mop:method-specializers object
)))))
438 (interpreted-function
440 (let ((source (translate-source-location
441 (sb-eval:interpreted-function-source-location object
))))
444 (translate-source-location (sb-interpreter:fun-source-location object
)))
446 (find-function-definition-source object
))
447 ((or condition standard-object structure-object
)
448 (find-definition-source (class-of object
)))
450 (error "Don't know how to retrieve source location for a ~S"
453 (defun find-function-definition-source (function)
454 (let* ((debug-source (debug-info-source (function-debug-info function
)))
455 (debug-fun (sb-di::fun-debug-fun function
))
456 (tlf (sb-c::compiled-debug-fun-tlf-number
457 (sb-di::compiled-debug-fun-compiler-debug-fun debug-fun
))))
458 (make-definition-source
460 (when (stringp (sb-c::debug-source-namestring debug-source
))
461 (parse-namestring (sb-c::debug-source-namestring debug-source
)))
464 (elt (sb-c::debug-source-start-positions debug-source
) tlf
))
465 :form-path
(if tlf
(list tlf
))
466 :form-number
(handler-case (sb-di::code-location-form-number
467 (sb-di::debug-fun-start-location debug-fun
))
468 (sb-di::unknown-code-location
(cond)
469 (declare (ignore cond
))
470 (sb-c::compiled-debug-fun-blocks
471 (sb-di::compiled-debug-fun-compiler-debug-fun debug-fun
))))
472 :file-write-date
(sb-c::debug-source-created debug-source
)
473 :plist
(sb-c::debug-source-plist debug-source
))))
475 (defun translate-source-location (location)
477 (make-definition-source
478 :pathname
(let ((n (sb-c:definition-source-location-namestring location
)))
480 (parse-namestring n
)))
482 (let ((number (sb-c:definition-source-location-toplevel-form-number
486 :form-number
(sb-c:definition-source-location-form-number
488 :plist
(sb-c:definition-source-location-plist location
))
489 (make-definition-source)))
491 (define-deprecated-function :late
"1.0.24.5" function-arglist function-lambda-list
493 (function-lambda-list function
))
495 (defun function-lambda-list (function)
496 "Return the lambda list for the extended function designator FUNCTION.
497 Works for special-operators, macros, simple functions, interpreted functions,
498 and generic functions. Signals an error if FUNCTION is not a valid extended
501 If the function does not have a lambda list (compiled with debug 0),
502 then two values are returned: (values nil t)"
503 (cond ((and (symbolp function
) (special-operator-p function
))
504 (function-lambda-list (info :function
:ir1-convert function
)))
505 ((valid-function-name-p function
)
506 (function-lambda-list (or (and (symbolp function
)
507 (macro-function function
))
508 (fdefinition function
))))
509 ((typep function
'generic-function
)
510 (sb-pcl::generic-function-pretty-arglist function
))
512 (let ((raw-result (%fun-lambda-list function
)))
513 (if (eq raw-result
:unknown
)
515 (values raw-result nil
))))))
517 (defun deftype-lambda-list (typespec-operator)
518 "Returns the lambda list of TYPESPEC-OPERATOR as first return
519 value, and a flag whether the arglist could be found as second
521 (check-type typespec-operator symbol
)
522 ;; Don't return a lambda-list for combinators AND,OR,NOT.
523 (let* ((f (and (info :type
:kind typespec-operator
)
524 (info :type
:expander typespec-operator
)))
525 (f (if (listp f
) (car f
) f
)))
527 (values (%fun-lambda-list f
) t
)
530 (defun method-combination-lambda-list (method-combination)
531 "Return the lambda-list of METHOD-COMBINATION designator.
532 METHOD-COMBINATION can be a method combination object,
533 or a method combination name."
534 (let* ((name (etypecase method-combination
535 (symbol method-combination
)
537 (sb-pcl::method-combination-type-name method-combination
))))
538 (info (or (gethash name sb-pcl
::**method-combinations
**)
539 (error "~S: no such method combination." name
))))
540 (sb-pcl::method-combination-info-lambda-list info
)))
542 (defun function-type (function-designator)
543 "Returns the ftype of FUNCTION-DESIGNATOR, or NIL."
544 (etypecase function-designator
546 ;; XXX: why require FBOUNDP? Would it be wrong to always report the proclaimed type?
547 (when (and (legal-fun-name-p function-designator
) ; guarding FBOUNDP against error
548 (fboundp function-designator
)
549 (eq (info :function
:kind function-designator
) :function
))
550 (type-specifier (global-ftype function-designator
))))
552 (let ((name (%fun-name function-designator
)))
553 (if (and (legal-fun-name-p name
)
555 ;; It seems inappropriate to report the global ftype if this
556 ;; function is not the current binding of the global name,
557 (eq (fdefinition name
) function-designator
))
558 ;; Give declared type in globaldb priority over derived type
559 ;; because it contains more accurate information e.g. for
562 (sb-impl::%fun-ftype function-designator
))))))
564 ;;;; find callers/callees, liberated from Helmut Eller's code in SLIME
566 ;;; This interface is tremendously experimental.
568 ;;; For the moment I'm taking the view that FDEFN is an internal
569 ;;; object (one out of one CMUCL developer surveyed didn't know what
570 ;;; they were for), so these routines deal in FUNCTIONs
572 ;;; Find callers and callees by looking at the constant pool of
573 ;;; compiled code objects. We assume every fdefn object in the
574 ;;; constant pool corresponds to a call to that function. A better
575 ;;; strategy would be to use the disassembler to find actual
578 (defun find-function-callees (function)
579 "Return functions called by FUNCTION."
580 (if (typep function
'generic-function
)
581 (loop for method in
(sb-mop:generic-function-methods function
)
582 for method-fun
= (sb-mop:method-function method
)
583 append
(find-function-callees
584 (if (typep (%fun-name method-fun
) '(cons (eql sb-pcl
::call
)))
585 (sb-kernel:%closure-index-ref method-fun
0)
589 (fun-code-header (sb-kernel:%fun-fun function
))
592 (let ((fun (fdefn-fun obj
)))
594 (push fun callees
))))))
597 (defun find-function-callers (function &optional
(spaces '(:read-only
:static
599 #+immobile-code
:immobile
)))
600 "Return functions which call FUNCTION, by searching SPACES for code objects"
601 (let ((referrers '()))
602 (map-caller-code-components
606 (dotimes (i (code-n-entries code
))
607 (pushnew (%code-entry-point code i
) referrers
))))
612 #-
(and system-tlabs
(not mark-region-gc
))
614 (labels ((functoid-simple-fun (functoid)
615 ;; looks like this is supposed to ignore INTERPRETED-FUNCTION ?
617 (simple-fun functoid
)
619 (let ((fun (%closure-fun functoid
)))
620 (if (and (eq (%fun-name fun
) 'sb-impl
::encapsulation
))
622 (sb-impl::encapsulation-info-definition
623 (sb-impl::encapsulation-info functoid
)))
625 (defun map-simple-funs (function)
626 (let ((function (%coerce-callable-to-fun function
)))
627 (labels ((process (name value
)
628 (awhen (functoid-simple-fun value
)
629 (funcall function name it
))))
630 (call-with-each-globaldb-name
632 ;; Methods are processed with their generic function
633 (unless (typep name
'(cons (member sb-pcl
::slow-method sb-pcl
::fast-method
)))
634 (let ((f (or (and (symbolp name
) (macro-function name
))
635 (and (legal-fun-name-p name
) (fboundp name
)))))
638 (loop for method in
(sb-mop:generic-function-methods f
)
639 for fun
= (sb-pcl::safe-method-fast-function method
)
640 when fun do
(process (sb-kernel:%fun-name fun
) fun
)))
643 #+sb-xref-for-internals
644 (let ((info (info :function
:info name
)))
646 (loop for transform in
(sb-c::fun-info-transforms info
)
647 for fun
= (sb-c::transform-function transform
)
648 ;; Defined using :defun-only and a later %deftransform.
650 do
(process transform fun
))))))
651 #+sb-xref-for-internals
652 (sb-int:dohash
((name vop
) sb-c
::*backend-template-names
*)
653 (declare (ignore name
))
654 (let ((fun (sb-c::vop-info-generator-function vop
)))
656 (process vop fun
))))))))
657 (defun collect-xref (wanted-kind wanted-name
)
661 (binding* ((xrefs (%simple-fun-xrefs fun
) :exit-if-null
))
662 (sb-c:map-packed-xref-data
663 (lambda (xref-kind xref-name xref-form-number
)
664 (when (and (eq xref-kind wanted-kind
)
665 (equal xref-name wanted-name
))
666 (let ((source-location (find-function-definition-source fun
)))
667 ;; Use the more accurate source path from the xref
669 (setf (definition-source-form-number source-location
)
671 (let ((name (cond ((sb-c::transform-p name
)
672 (let ((fun-name (%fun-name fun
)))
673 (append (if (consp fun-name
)
676 (let* ((type (sb-c::transform-type name
))
677 (type-spec (type-specifier type
)))
678 (and (sb-kernel:fun-type-p type
)
679 (list (second type-spec
)))))))
680 ((sb-c::vop-info-p name
)
681 (list 'sb-c
:define-vop
682 (sb-c::vop-info-name name
)))
685 (push (cons name source-location
) result
)))))
689 #+(and system-tlabs
(not mark-region-gc
))
691 (sb-ext:defglobal
*codeblob-cache
* nil
)
692 (flet ((gather-code (stamp) ; = the value of sb-vm::*code-alloc-count*
693 ;; Remove unreachable functions.
695 (let ((arena (sb-vm:new-arena
(* 2 1024 1024)))
697 ;; Can allocate inside an arena while holding without-gcing in sb-vm:map-code-objects
698 ;; Anyway this approach is silly because Lisp should maintain at all times
699 ;; a binary-searchable tree of all code which would solve all problems
700 ;; related to finding a codeblob from a PC without relying on whatever
701 ;; a particular GC implementation exposes in terms of linearly searchable
702 ;; ranges of memory. immobile-space does maintain such a tree. Of course the tree
703 ;; should also _weakly_ reference all code, and should be usable for xref
704 ;; and other consumers beside the debugger. And it should come with a pony too.
706 (sb-vm:with-arena
(arena)
707 ;; No filtering since we want this to pertain to all COLLECT-XREFS calls
708 (sb-vm:map-code-objects
(lambda (code) (push code result
))))
709 ;; arenas are not suitable for returning memoized data
710 (setq result
(coerce result
'vector
))
711 (sb-vm:destroy-arena arena
))
712 (setf *codeblob-cache
* (cons stamp
(sb-ext:make-weak-pointer result
)))
714 (defun collect-xref (wanted-kind wanted-name
)
715 (let* ((current-stamp sb-vm
::*code-alloc-count
*)
717 ;; this is not an attempt to be 100% correct in observing an up-to-date
718 ;; snapshot at a point in time. It's close enough though.
719 ;; I can't imagine that users are clamoring for a perfect solution to
720 ;; racing threads and XREFing jit-compiled code.
721 (or (let ((cache *codeblob-cache
*))
722 (and (eql (car cache
) current-stamp
)
723 (sb-ext:weak-pointer-value
(cdr cache
))))
724 (loop ; expect exactly 1 iteration
725 (let ((vector (gather-code current-stamp
))
726 (new-stamp sb-vm
::*code-alloc-count
*))
727 (if (eq new-stamp current-stamp
) ; say it's done
729 (setq current-stamp new-stamp
))))))
731 (dovector (code all-code
)
732 (dotimes (i (code-n-entries code
))
733 (let ((fun (%code-entry-point code i
)))
734 (binding* ((xrefs (%simple-fun-xrefs fun
) :exit-if-null
))
735 (sb-c:map-packed-xref-data
736 (lambda (xref-kind xref-name xref-form-number
)
737 (when (and (eq xref-kind wanted-kind
)
738 (equal xref-name wanted-name
))
739 (push (cons fun xref-form-number
) funs
)))
742 (loop for
(fun . xref-form-number
) in funs
744 (let ((source-location (find-function-definition-source fun
)))
745 ;; Use the more accurate source path from the xref
747 (setf (definition-source-form-number source-location
) xref-form-number
)
748 (let* ((name (sb-c::%fun-name fun
))
749 (name (cond ((typep name
'(cons (eql sb-c
:deftransform
)))
750 (let* ((fun-name (second name
))
751 (info (sb-int:info
:function
:info fun-name
))
753 (find fun
(sb-c::fun-info-transforms info
)
754 :key
#'sb-c
::transform-function
))))
757 (let* ((type (sb-c::transform-type transform
))
758 (type-spec (type-specifier type
)))
759 (and (sb-kernel:fun-type-p type
)
760 (list (second type-spec
)))))
764 (pushnew (cons name source-location
) result
:test
#'equalp
))))
767 (defun who-calls (function-name)
768 "Use the xref facility to search for source locations where the
769 global function named FUNCTION-NAME is called. Returns a list of
770 function name, definition-source pairs."
771 (collect-xref :calls function-name
))
773 (defun who-binds (symbol)
774 "Use the xref facility to search for source locations where the
775 special variable SYMBOL is rebound. Returns a list of function name,
776 definition-source pairs."
777 (collect-xref :binds symbol
))
779 (defun who-references (symbol)
780 "Use the xref facility to search for source locations where the
781 special variable or constant SYMBOL is read. Returns a list of function
782 name, definition-source pairs."
783 (collect-xref :references symbol
))
785 (defun who-sets (symbol)
786 "Use the xref facility to search for source locations where the
787 special variable SYMBOL is written to. Returns a list of function name,
788 definition-source pairs."
789 (collect-xref :sets symbol
))
791 (defun who-macroexpands (macro-name)
792 "Use the xref facility to search for source locations where the
793 macro MACRO-NAME is expanded. Returns a list of function name,
794 definition-source pairs."
795 (collect-xref :macroexpands macro-name
))
797 (defun who-specializes-directly (class-designator)
798 "Search for source locations of methods directly specializing on
799 CLASS-DESIGNATOR. Returns an alist of method name, definition-source
802 A method matches the criterion either if it specializes on the same
803 class as CLASS-DESIGNATOR designates (this includes CLASS-EQ
804 specializers), or if it eql-specializes on an instance of the
809 (let ((class (canonicalize-class-designator class-designator
)))
811 (return-from who-specializes-directly nil
))
812 (let ((result (collect-specializing-methods
814 ;; Does SPECL specialize on CLASS directly?
816 (sb-pcl::class-eq-specializer
817 (eq (sb-pcl::specializer-object specl
) class
))
818 (sb-pcl::eql-specializer
819 (let ((obj (sb-mop:eql-specializer-object specl
)))
820 (eq (class-of obj
) class
)))
821 ((not sb-pcl
::standard-specializer
)
824 (eq specl class
)))))))
825 (map-into result
#'(lambda (m)
826 (cons `(method ,(method-generic-function-name m
))
827 (find-definition-source m
)))
830 (defun who-specializes-generally (class-designator)
831 "Search for source locations of methods specializing on
832 CLASS-DESIGNATOR, or a subclass of it. Returns an alist of method
833 name, definition-source pairs.
835 A method matches the criterion either if it specializes on the
836 designated class itself or a subclass of it (this includes CLASS-EQ
837 specializers), or if it eql-specializes on an instance of the
838 designated class or a subclass of it.
842 (let ((class (canonicalize-class-designator class-designator
)))
844 (return-from who-specializes-generally nil
))
845 (let ((result (collect-specializing-methods
847 ;; Does SPECL specialize on CLASS or a subclass
850 (sb-pcl::class-eq-specializer
851 (subtypep (sb-pcl::specializer-object specl
) class
))
852 (sb-pcl::eql-specializer
853 (typep (sb-mop:eql-specializer-object specl
) class
))
854 ((not sb-pcl
::standard-specializer
)
857 (subtypep specl class
)))))))
858 (map-into result
#'(lambda (m)
859 (cons `(method ,(method-generic-function-name m
))
860 (find-definition-source m
)))
863 (defun canonicalize-class-designator (class-designator)
864 (typecase class-designator
865 (symbol (find-class class-designator nil
))
866 (class class-designator
)
869 (defun method-generic-function-name (method)
870 (sb-mop:generic-function-name
(sb-mop:method-generic-function method
)))
872 (defun collect-specializing-methods (predicate)
874 (sb-pcl::map-specializers
876 (when (funcall predicate specl
)
877 (let ((methods (sb-mop:specializer-direct-methods specl
)))
878 (setf result
(append methods result
))))))
879 (delete-duplicates result
)))
882 ;;;; ALLOCATION INTROSPECTION
884 (eval-when (:compile-toplevel
:execute
)
885 (defmacro pinnedp
(addr)
886 `(eql (sb-alien:alien-funcall
887 (sb-alien:extern-alien
"sb_introspect_pinnedp"
888 (function sb-alien
:int sb-alien
:unsigned
))
892 (defun allocation-information (object)
893 "Returns information about the allocation of OBJECT. Primary return value
894 indicates the general type of allocation: :IMMEDIATE, :HEAP, :STACK,
897 Possible secondary return value provides additional information about the
900 For :HEAP objects the secondary value is a plist:
903 Indicates the heap segment the object is allocated in.
906 Is the current generation of the object: 0 for nursery, 6 for pseudo-static
907 generation loaded from core. (GENCGC and :SPACE :DYNAMIC only.)
910 Indicates a \"large\" object subject to non-copying
911 promotion. (GENCGC and :SPACE :DYNAMIC only.)
914 Indicates that the object is allocated in a boxed region. Unboxed
915 allocation is used for eg. specialized arrays after they have survived one
916 collection. (GENCGC and :SPACE :DYNAMIC only.)
919 Indicates that the page(s) on which the object resides are kept live due
920 to conservative references. Note that object may reside on a pinned page
921 even if :PINNED in NIL if the GC has not had the need to mark the the page
922 as pinned. (GENCGC and :SPACE :DYNAMIC only.)
925 Indicates that the page on which the object starts is write-protected,
926 which indicates for :BOXED objects that it hasn't been written to since
927 the last GC of its generation. (GENCGC and :SPACE :DYNAMIC only.)
930 The index of the page the object resides on. (GENGC and :SPACE :DYNAMIC
933 For :STACK objects secondary value is the thread on whose stack the object is
936 Expected use-cases include introspection to gain insight into allocation and
937 GC behaviour and restricting memoization to heap-allocated arguments.
939 Experimental: interface subject to change."
940 ;; FIXME: Would be nice to provide the size of the object as well, though
941 ;; maybe that should be a separate function, and something like MAP-PARTS
942 ;; for mapping over parts of arbitrary objects so users can get "deep sizes"
943 ;; as well if they want to.
945 (if (not (sb-vm:is-lisp-pointer
(get-lisp-obj-address object
)))
946 (values :immediate nil
)
948 (sb-sys:with-pinned-objects
(object)
949 (let ((space (sb-ext:heap-allocated-p object
)))
952 (if (eq :dynamic space
)
953 (symbol-macrolet ((page (sb-alien:deref sb-vm
::page-table index
)))
954 ;; No wonder #+big-endian failed introspection tests-
955 ;; bits are packed in the opposite order. And thankfully,
956 ;; this fix seems not to depend on whether the numbering
957 ;; scheme is MSB 0 or LSB 0, afaict.
958 (let* ((wp (page-protected-p object
))
959 (index (sb-vm:find-page-index
960 (get-lisp-obj-address object
)))
961 (type (sb-alien:slot page
'sb-vm
::flags
)))
963 :generation
(sb-alien:slot page
'sb-vm
::gen
)
965 :boxed
(> (logand type
#xf
) 1)
966 :pinned
(pinnedp (get-lisp-obj-address object
))
967 :large
(logbitp 4 type
)
971 (list :space space
))))))
973 (values :heap plist
))
976 (let ((thread (sb-ext:stack-allocated-p object t
)))
978 (return-from allocation-information
979 (values :stack thread
))))
981 (when (sb-vm:control-stack-pointer-valid-p
982 (sb-sys:int-sap
(get-lisp-obj-address object
)) nil
)
983 (return-from allocation-information
984 (values :stack sb-thread
::*current-thread
*)))
987 (defun map-root (function object
&key simple
(ext t
))
988 "Call FUNCTION with all non-immediate objects pointed to by OBJECT.
991 If SIMPLE is true (default is NIL), elides those pointers that are not
992 notionally part of certain built-in objects, but backpointers to a
993 conceptual parent: eg. elides the pointer from a SYMBOL to the
994 corresponding PACKAGE.
996 If EXT is true (default is T), includes some pointers that are not
997 actually contained in the object, but found in certain well-known
998 indirect containers: FDEFINITIONs, EQL specializers, classes, and
999 thread-local symbol values in other threads fall into this category.
1001 NOTE: calling MAP-ROOT with a THREAD does not currently map over
1002 conservative roots from the thread registers and interrupt contexts.
1004 Experimental: interface subject to change."
1005 (when (typep object
'(or bignum float sb-sys
:system-area-pointer
1007 (return-from map-root object
))
1008 (let ((fun (coerce function
'function
))
1009 (seen (alloc-xset)))
1011 (when (and (sb-vm:is-lisp-pointer
(get-lisp-obj-address part
))
1012 (not (xset-member-p part seen
)))
1013 (add-to-xset part seen
)
1014 (funcall fun part
))))
1015 (declare (dynamic-extent #'call
))
1017 (multiple-value-bind (value foundp
)
1018 (let ((table sb-pcl
::*eql-specializer-table
*))
1019 (with-system-mutex ((hash-table-lock table
))
1020 (gethash object table
)))
1021 (when foundp
(call value
))))
1022 (sb-vm:do-referenced-object
(object call
)
1025 (when (and ext
(ignore-errors (fboundp object
)))
1026 (call (fdefinition object
))))
1030 (when (typep object
'sb-thread
:thread
)
1031 (cond ((eq object sb-thread
:*current-thread
*)
1032 (dolist (value (sb-thread::%thread-local-references
))
1034 (sb-vm::map-stack-references
#'call
))
1036 ;; KLUDGE: INTERRUPT-THREAD is Not Nice (tm), but
1037 ;; the alternative would be stopping the world...
1038 (let ((sem (sb-thread:make-semaphore
))
1042 (sb-thread:interrupt-thread
1045 (setf refs
(sb-thread::%thread-local-references
))
1046 (sb-vm::map-stack-references
(lambda (x) (push x refs
)))
1047 (sb-thread:signal-semaphore sem
)))
1048 (sb-thread:wait-on-semaphore sem
))
1049 (sb-thread:interrupt-thread-error
()))
1050 ;; This is whacky - the other thread signals our condition var,
1051 ;; *then* we call the funarg on objects that may no longer
1052 ;; satisfy VALID-TAGGED-POINTER-P.
1053 ;; And incidentally, we miss any references from TLS indices
1054 ;; that map onto the 'struct thread', which is just as well
1055 ;; since they're either fixnums or dynamic-extent objects.
1056 (mapc #'call refs
))))))
1057 ((satisfies array-header-p
)
1059 ;; The default implementation always scans %array-displaced-from
1060 (call (%array-data object
))
1061 (call (%array-displaced-p object
))
1063 (call (%array-displaced-from object
))))
1066 (loop for i below
(code-n-entries object
)
1067 do
(call (%code-entry-point object i
))))
1068 (function ; excluding CLOSURE and FUNCALLABLE-INSTANCE
1071 (call (fun-code-header object
)))
1072 (call (%simple-fun-name object
))
1073 (call (%simple-fun-arglist object
))
1074 (call (%simple-fun-source object
))
1075 (call (%simple-fun-info object
)))
1077 ;; We use :override here because (apparently) the intent is
1078 ;; to avoid calling FUNCTION on the SYMBOL-PACKAGE
1079 ;; when SIMPLE is NIL (the default). And we skip SYMBOL-EXTRA for
1080 ;; the same reason that we don't call FUNCTION on SYMBOL-INFO
1081 ;; (logically it's "system" data, not for user consumption).
1082 ;; Frankly this entire function is a confusing mishmash that is not
1083 ;; accurate for computing a true graph of objects starting from a
1084 ;; certain point, given all the special cases that it implements.
1087 (dolist (thread (sb-thread:list-all-threads
))
1088 (call (sb-thread:symbol-value-in-thread object thread nil
))))
1089 (call (sb-sys:%primitive sb-c
:fast-symbol-global-value object
))
1090 ;; These first two are probably unnecessary.
1091 ;; The functoid values, if present, are in SYMBOL-INFO
1092 ;; which is traversed whether or not EXT was true.
1093 ;; But should we traverse SYMBOL-INFO?
1094 ;; I don't know what is expected of this interface.
1095 (when (and ext
(ignore-errors (fboundp object
)))
1096 (call (fdefinition object
))
1097 (call (macro-function object
))
1098 (let ((class (find-class object nil
)))
1099 (when class
(call class
))))
1100 (call (symbol-plist object
)) ; perhaps SB-KERNEL:SYMBOL-INFO instead?
1101 (call (symbol-name object
))
1103 (call (symbol-package object
))))
1106 (case (widetag-of object
)
1107 (#.sb-vm
:value-cell-widetag
1108 (call (value-cell-ref object
)))
1110 (warn "~&MAP-ROOT: Unknown widetag ~S: ~S~%"
1111 (widetag-of object
) object
)))))))
1114 (defun object-size (object)
1115 (+ (primitive-object-size object
)
1117 (sb-mop:funcallable-standard-object
1118 (primitive-object-size (sb-pcl::fsc-instance-slots object
)))
1120 (primitive-object-size (sb-pcl::std-instance-slots object
)))
1123 ;;; Print a distribution of object sizes in SPACE.
1124 ;;; There are two bins for cons-sized objects: conses and anything else,
1125 ;;; the latter including SAPs, value cells, 0-length simple-vectors,
1126 ;;; and a bunch of other things.
1127 (defun object-size-histogram (&optional
1129 (size-bins ; objects whose size in words is <= this
1130 `#(2 4 6 8 10 16 20 24 32 64 128 256 512 1024
1131 2048 4096 8192 16384 32768 131072 524288
1132 ,(ash 1 20) ,(ash 1 21) ,(ash 1 23))))
1133 (declare (simple-vector size-bins
))
1134 (let* ((n-bins (+ (length size-bins
) 2))
1135 (counts (make-array n-bins
:initial-element
0))
1136 (size-totals (make-array n-bins
:initial-element
0)))
1137 (sb-vm:map-allocated-objects
1138 (lambda (obj type size
)
1139 (declare (ignore type
))
1141 (incf (aref counts
0)))
1143 (let* ((words (ash size
(- sb-vm
:word-shift
)))
1145 (let ((i (position words size-bins
:test
#'<=)))
1146 (if i
(1+ i
) (1- n-bins
)))))
1147 (incf (aref counts bin
))
1148 (incf (aref size-totals bin
) words
)))))
1150 (format t
" Freq Tot Words~% ========= =========~%")
1152 (format t
" ~9d ~11d ~a~%"
1154 (if (eql i
0) ; cons bin
1155 (* 2 (aref counts i
))
1156 (aref size-totals i
))
1157 (cond ((zerop i
) "cons")
1158 ((eql i
(1- n-bins
))
1159 (format nil
" > ~D" (aref size-bins
(- n-bins
3))))
1161 (let ((this-bin-size (aref size-bins
(1- i
)))
1162 (prev-bin-size (when (>= i
2) (aref size-bins
(- i
2)))))
1163 (format nil
"~:[<=~;=~] ~D"
1164 (or (not prev-bin-size
)
1165 (= this-bin-size
(+ prev-bin-size
2)))
1166 this-bin-size
))))))))
1168 (defun largest-objects (&key
(threshold #+generational sb-vm
:gencgc-page-bytes
1169 #-generational sb-c
:+backend-page-bytes
+)
1171 (declare (type (member :address
:size
) sort
))
1172 (flet ((show-obj (obj)
1174 (format t
"~10x ~7x ~s~%"
1175 (get-lisp-obj-address obj
)
1176 (primitive-object-size obj
)
1179 (let* ((gen (generation-of obj
))
1180 (page (sb-vm::find-page-index
(sb-kernel:get-lisp-obj-address obj
)))
1181 (flags (if (>= page
0)
1182 (sb-alien:slot
(sb-alien:deref sb-vm
:page-table page
)
1184 (format t
"~10x ~7x ~a ~:[ ~;~:*~8b~] ~s~%"
1185 (get-lisp-obj-address obj
)
1186 (primitive-object-size obj
)
1192 (sb-vm:map-allocated-objects
1193 (lambda (obj widetag size
)
1194 (declare (ignore widetag
))
1195 (when (>= size threshold
)
1200 (sb-vm:map-allocated-objects
1201 (lambda (obj widetag size
)
1202 (declare (ignore widetag
))
1203 (when (>= size threshold
)
1207 (stable-sort list
#'> :key
#'primitive-object-size
))