X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=contrib%2Fsb-introspect%2Fsb-introspect.lisp;h=1ca2d2ab3a92bbb6c8efbbee74d11a72aa9428c9;hb=bea5b384106a6734a4b280a76e8ebdd4d51b5323;hp=33a580ecea53f2f150e9c560b31f9cd7c5099794;hpb=85c1cf858999279da6f4f470c4f3c582ad9f2dbf;p=sbcl.git diff --git a/contrib/sb-introspect/sb-introspect.lisp b/contrib/sb-introspect/sb-introspect.lisp index 33a580e..1ca2d2a 100644 --- a/contrib/sb-introspect/sb-introspect.lisp +++ b/contrib/sb-introspect/sb-introspect.lisp @@ -34,6 +34,8 @@ "DEFINITION-NOT-FOUND" "DEFINITION-NAME" "DEFINITION-SOURCE-FORM-PATH" "DEFINITION-SOURCE-CHARACTER-OFFSET" + "FIND-FUNCTION-CALLEES" + "FIND-FUNCTION-CALLERS" )) (in-package :sb-introspect) @@ -42,10 +44,11 @@ "True if NAME denotes a function name that can be passed to MACRO-FUNCTION or FDEFINITION " (and (sb-int:valid-function-name-p name) t)) +;;; FIXME: maybe this should be renamed as FUNCTION-LAMBDA-LIST? (defun function-arglist (function) "Describe the lambda list for the function designator FUNCTION. -Works for macros, simple functions and generic functions. Signals error -if not found" +Works for special-operators, macros, simple functions and generic +functions. Signals error if not found" (cond ((valid-function-name-p function) (function-arglist (or (macro-function function) (fdefinition function)))) @@ -160,3 +163,83 @@ Returns a DEFINITION-SOURCE object")) (sb-int:info :type :classoid (class-name o)))))) (find-definition-source constructor))) +;;;; find callers/callees, liberated from Helmut Eller's code in SLIME + +;;; This interface is trmendously experimental. + +;;; For the moment I'm taking the view that FDEFN is an internal +;;; object (one out of one CMUCL developer surveyed didn't know what +;;; they were for), so these routines deal in FUNCTIONs + +;;; Find callers and callees by looking at the constant pool of +;;; compiled code objects. We assume every fdefn object in the +;;; constant pool corresponds to a call to that function. A better +;;; strategy would be to use the disassembler to find actual +;;; call-sites. + +(declaim (inline map-code-constants)) +(defun map-code-constants (code fn) + "Call FN for each constant in CODE's constant pool." + (check-type code sb-kernel:code-component) + (loop for i from sb-vm:code-constants-offset below + (sb-kernel:get-header-data code) + do (funcall fn (sb-kernel:code-header-ref code i)))) + +(defun find-function-callees (function) + "Return functions called by FUNCTION." + (let ((callees '())) + (map-code-constants + (sb-kernel:fun-code-header function) + (lambda (obj) + (when (sb-kernel:fdefn-p obj) + (push (sb-kernel:fdefn-fun obj) + callees)))) + callees)) + +(declaim (inline map-allocated-code-components)) +(defun map-allocated-code-components (spaces fn) + "Call FN for each allocated code component in one of SPACES. FN +receives the object and its size as arguments. SPACES should be a +list of the symbols :dynamic, :static, or :read-only." + (dolist (space spaces) + (sb-vm::map-allocated-objects + (lambda (obj header size) + (when (= sb-vm:code-header-widetag header) + (funcall fn obj size))) + space))) + +(declaim (inline map-caller-code-components)) +(defun map-caller-code-components (function spaces fn) + "Call FN for each code component with a fdefn for FUNCTION in its +constant pool." + (let ((function (coerce function 'function))) + (map-allocated-code-components + spaces + (lambda (obj size) + (declare (ignore size)) + (map-code-constants + obj + (lambda (constant) + (when (and (sb-kernel:fdefn-p constant) + (eq (sb-kernel:fdefn-fun constant) + function)) + (funcall fn obj)))))))) + +(defun find-function-callers (function &optional (spaces '(:read-only :static + :dynamic))) + "Return functions which call FUNCTION, by searching SPACES for code objects" + (let ((referrers '())) + (map-caller-code-components + function + spaces + (lambda (code) + (let ((entry (sb-kernel:%code-entry-points code))) + (cond ((not entry) + (push (princ-to-string code) referrers)) + (t + (loop for e = entry then (sb-kernel::%simple-fun-next e) + while e + do (pushnew e referrers))))))) + referrers)) + +(provide 'sb-introspect)