File: cross-referencing.tex

package info (click to toggle)
sbcl 2%3A2.2.9-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 45,620 kB
  • sloc: lisp: 466,598; ansic: 34,134; sh: 5,019; asm: 2,124; makefile: 418; pascal: 207; cpp: 27
file content (297 lines) | stat: -rw-r--r-- 11,300 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
\chapter{Cross-Referencing Facility}
\label{xref}
\cindex{cross-referencing}
\credits{by Eric Marsden}

The \cmucl{} cross-referencing facility (abbreviated XREF) assists in
the analysis of static dependency relationships in a program. It
provides introspection capabilities such as the ability to know which
functions may call a given function, and the program contexts in which
a particular global variable is used. The compiler populates a
database of cross-reference information, which can be queried by the
user to know:

\begin{itemize}
\item
the list of program contexts (functions, macros, top-level forms)
where a given function may be called at runtime, either directly or
indirectly (via its function-object);

\item
the list of program contexts where a given global variable may be
read;

\item
the list of program contexts that bind a global variable;

\item
the list of program contexts where a given global variable may be
modified during the execution of the program.
\end{itemize}

A global variable is either a dynamic variable or a constant variable,
for instance declared using \code{defvar} or \code{defparameter} or
\code{defconstant}.


\section{Populating the cross-reference database}

\begin{defvar}{c:}{record-xref-info}
   When non-NIL, code that is compiled (either using
   \code{compile-file}, or by calling \code{compile} from the
   listener), will be analyzed for cross-references. Defaults to
   \nil{}.
\end{defvar}

Cross-referencing information is only generated by the compiler; the
interpreter does not populate the cross-reference database. XREF
analysis is independent of whether the compiler is generating native
code or byte code, and of whether it is compiling from a file, from a
stream, or is invoked interactively from the listener. 

Alternatively, the \kwd{:xref} option to \code{compile-file} may be
specified to populate the cross-reference database when compiling a
file.  In this case, loading the generated fasl file in a fresh lisp
will also populate the cross-reference database.

\begin{defun}{xref:}{init-xref-database}{}
  Reinitializes the database of cross-references. This can be used to
  reclaim the space occupied by the database contents, or to discard
  stale cross-reference information.
\end{defun}



\section{Querying the cross-reference database}

\cmucl{} provides a number of functions in the XREF package that may
be used to query the cross-reference database:

\begin{defun}{xref:}{who-calls}{\args \var{function}}
   Returns the list of xref-contexts where \var{function} (either a
   symbol that names a function, or a function object) may be called
   at runtime. XREF does not record calls to macro-functions (such as
   \code{defun}) or to special forms (such as \code{eval-when}).
\end{defun}

\begin{defun}{xref:}{who-references}{\args \var{global-variable}}
   Returns the list of program contexts that may reference
   \var{global-variable}. 
\end{defun}

\begin{defun}{xref:}{who-binds}{\args \var{global-variable}}
  Returns a list of program contexts where the specified global
  variable may be bound at runtime (for example using \code{LET}).
\end{defun}

\begin{defun}{xref:}{who-sets}{\args \var{global-variable}}
  Returns a list of program contexts where the given global variable
  may be modified at runtime (for example using \code{SETQ}). 
\end{defun}

An \textit{xref-context} is the originating site of a cross-reference.
It identifies a portion of a program, and is defined by an
\code{xref-context} structure, that comprises a name, a source file and a
source-path. 

\begin{defun}{xref:}{xref-context-name}{\args \var{context}}
  Returns the name slot of an xref-context, which is one of:
\begin{itemize}
\item
a global function, which is named by a symbol or by a list of the form
\code{(setf\ foo)}. 

\item
a macro, named by a list \verb|(:macro foo)|.

\item
an inner function (\code{flet}, \code{labels}, or anonymous lambdas) that
is named by a list of the form \code{(:internal outer inner)}.

\item
a method, named by a list of the form
\verb|(:method foo (specializer1 specializer2)|. 

\item
a string \verb|"Top-Level Form"| that identifies a reference from a
top-level form. Note that multiple references from top-level forms
will only be listed once. 

\item
a compiler-macro, named by a string of the form
\verb|(:compiler-macro foo)|. 

\item
a string such as \verb|"DEFSTRUCT FOO"|, identifying a reference from
within a structure accessor or constructor or copier.

\item
a string such as 
\begin{verbatim}
  "Creation Form for #<KERNEL::CLASS-CELL STRUCT-FOO>"
\end{verbatim}

\item
a string such as \verb|"defun foo"|, or \verb|"defmethod bar (t)"|,
that identifies a reference from within code that has been generated
by the compiler for that form. For example, the compilation of a
\code{defclass} form causes accessor functions to be generated by the
compiler; this code is compiler-generated (it does not appear in the
source file), and so is identified by the XREF facility by a string. 
\end{itemize}
\end{defun}


\begin{defun}{xref:}{xref-context-file}{\var{context}}
  Return the truename (in the sense of the variable
   \vindexed{compile-file-truename}) of the source file from which the
   referencing forms were compiled. This slot will be \nil{} if the
   code was compiled from a stream, or interactively from the
   listener.
\end{defun}

\begin{defun}{xref:}{xref-context-source-path}{\var{context}}
  Return a list of positive integers identifying the form that
  contains the cross-reference. The first integer in the source-path
  is the number of the top-level form containing the cross-reference
  (for example, 2 identifies the second top-level form in the source
  file). The second integer in the source-path identifies the form
  within this top-level form that contains the cross-reference, and so
  on. This function will always return \nil{} if the file slot of an
  xref-context is \nil{}.

% While walking the top-level form, count one in depth-first order for
% each subform that is a cons.
\end{defun}




\section{Example usage}

In this section, we will illustrate use of the XREF facility on a
number of simple examples.

Consider the following program fragment, that defines a global
variable and a function.

\begin{verbatim}
  (defvar *variable-one* 42)
  
  (defun function-one (x)
     (princ (* x *variable-one*)))
\end{verbatim}

We save this code in a file named \code{example.lisp}, enable
cross-referencing, clear any previous cross-reference information,
compile the file, and can then query the cross-reference database
(output has been modified for readability).

\begin{verbatim}
  USER> (setf c:*record-xref-info* t)
  USER> (xref:init-xref-database)
  USER> (compile-file "example")
  USER> (xref:who-calls 'princ)
  (#<xref-context function-one in #p"example.lisp">)
  USER> (xref:who-references '*variable-one*)
  (#<xref-context function-one in #p"example.lisp">)
\end{verbatim}

From this example, we see that the compiler has noted the call to the
global function \code{princ} in \code{function-one}, and the reference
to the global variable \code{*variable-one*}. 

Suppose that we add the following code to the previous file. 

\begin{verbatim}
(defconstant +constant-one+ 1)
  
(defstruct struct-one
  slot-one
  (slot-two +constant-one+ :type integer)
  (slot-three 42 :read-only t))

(defmacro with-different-one (&body body)
  `(let ((*variable-one* 666))
      ,@body))

(defun get-variable-one () *variable-one*)

(defun (setf get-variable-one) (new-value)
  (setq *variable-one* new-value))
\end{verbatim}

In the following example, we detect references x and y.


% FIXME add function with LABELS, a binding, a set



The following function illustrates the effect that various forms of
optimization carried out by the \cmucl{} compiler can have on the
cross-references that are reported for a particular program. The
compiler is able to detect that the evaluated condition is always
false, and that the first clause of the \code{if} will never be taken
(this optimization is called dead-code elimination). XREF will
therefore not register a call to the function \code{sin} from the
function \code{foo}. Likewise, no calls to the functions \code{sqrt}
and \code{\textless} are registered, because the compiler has eliminated the
code that evaluates the condition. Finally, no call to the function
\code{expt} is generated, because the compiler was able to evaluate
the result of the expression \code{(expt 3 2)} at compile-time (though
a process called constant-folding).

\begin{verbatim}
;; zero call references are registered for this function!
(defun constantly-nine (x)
  (if (< (sqrt x) 0)
      (sin x)
      (expt 3 2)))
\end{verbatim}


\section{Limitations of the cross-referencing facility}

No cross-reference information is available for interpreted functions.
The cross-referencing database is not persistent: unless you save an
image using \code{save-lisp}, the database will be empty each time
\cmucl{} is restarted. There is no mechanism that saves
cross-reference information in FASL files, so loading a system from
compiled code will not populate the cross-reference database. The XREF
database currently accumulates ``stale'' information: when compiling a
file, it does not delete any cross-references that may have previously
been generated for that file. This latter limitation will be removed
in a future release. 

The cross-referencing facility is only able to analyze the static
dependencies in a program; it does not provide any information about
runtime (dynamic) dependencies. For instance, XREF is able to identify
the list of program contexts where a given function may be called, but
is not able to determine which contexts will be activated when the
program is executed with a specific set of input parameters. However,
the static analysis that is performed by the \cmucl{} compiler does
allow XREF to provide more information than would be available from a
mere syntactic analysis of a program. References that occur from
within unreachable code will not be displayed by XREF, because the
\cmucl{} compiler deletes dead code before cross-references are
analyzed. Certain ``trivial'' function calls (where the result of the
function call can be evaluated at compile-time) may be eliminated by
optimizations carried out by the compiler; see the example below.

If you examine the entire database of cross-reference information (by
accessing undocumented internals of the XREF package), you will note
that XREF notes ``bogus'' cross-references to function calls that are
inserted by the compiler. For example, in safe code, the \cmucl{}
compiler inserts a call to an internal function called
\code{c::\%verify-argument-count}, so that the number of arguments
passed to the function is checked each time it is called. The XREF
facility does not distinguish between user code and these forms that
are introduced during compilation. This limitation should not be
visible if you use the documented functions in the XREF package. 

As of the 18e release of \cmucl{}, the cross-referencing facility is
experimental; expect details of its implementation to change in future
releases. In particular, the names given to CLOS methods and to inner
functions will change in future releases.