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