;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: 4Tracing Function Execution* =Text: 3TRACING FUNCTION EXECUTION* The trace facility allows the user to 1trace* some functions. When a function is traced, certain special actions are taken when it is called and when it returns. The default tracing action is to print a message when the function is called, showing its name and arguments, and another message when the function returns, showing its name and value(s). The trace facility is closely compatible with Maclisp. You invoke it through the 2trace* and 2untrace* special forms, whose syntax is described below. Alternatively, you can use the trace system by clicking 2Trace* in the system menu, or by using the 2Meta-X Trace* command in the editor. This allows you to select the trace options from a menu instead of having to remember the following syntax. 3trace* 1Special Form* A 2trace* form looks like: 3(trace 1spec-1* 1spec-2* ...)* Each 1spec* can take any of the following forms: 2a symbol* This is a function name, with no options. The function is traced in the default way, printing a message each time it is called and each time it returns. 2a list (1function-name* 1option-1* 1option-2* ...)* 1function-name* is a symbol and the 1options* control how it is to be traced. The various options are listed below. Some options take arguments, which should be given immediately following the option name. 2a list (:function 1function-spec* 1option-1* 1option-2* ...)* This is like the previous form except that 1function-spec* need not be a symbol (see 4(FUNCTIONS-1)Function Specs*). It exists because if 1function-name* was a list in the previous form, it would instead be interpreted as the following form: 2a list ((1function-1* 1function-2*...) 1option-1* 1option-2* ...)* All of the functions are traced with the same options. Each 1function* can be either a symbol or a general function-spec. The following 2trace* options exist: 2:break 1pred** Causes a breakpoint to be entered after printing the entry trace information but before applying the traced function to its arguments, if and only if 1pred* evaluates to non-2nil*. During the breakpoint, the symbol 2arglist* is bound to a list of the arguments of the function. 2:exitbreak 1pred** This is just like 2break* except that the breakpoint is entered after the function has been executed and the exit trace information has been printed, but before control returns. During the breakpoint, the symbol 2arglist* is bound to a list of the arguments of the function, and the symbol 2values* is bound to a list of the values that the function is returning. 2:error* Causes the error handler to be called when the function is entered. Use 2Resume* (or 2Control-C*) to continue execution of the function. If this option is specified, there is no printed trace output other than the error message printed by the error handler. This is semi-obsolete, as 2breakon* is more convenient and does more exactly the right thing. 2:step* Causes the function to be single-stepped whenever it is called. See the documentation on the step facility, 4(DEBUGGING-6)Stepping Through an Evaluation*. 2:stepcond 1pred** Causes the function to be single-stepped only if 1pred* evaluates to non-2nil*. 2:entrycond 1pred** Causes trace information to be printed on function entry only if 1pred* evaluates to non-2nil*. 2:exitcond 1pred** Causes trace information to be printed on function exit only if 1pred* evaluates to non-2nil*. 2:cond 1pred** This specifies both 2:exitcond* and 2:entrycond* together. 2:wherein 1function** Causes the function to be traced only when called, directly or indirectly, from the specified function 1function*. One can give several trace specs to 2trace*, all specifying the same function but with different 2wherein* options, so that the function is traced in different ways when called from different functions. This is different from 2advise-within*, which only affects the function being advised when it is called directly from the other function. The 2trace* 2:wherein* option means that when the traced function is called, the special tracing actions occur if the other function is the caller of this function, or its caller's caller, or its caller's caller's caller, etc. 2:argpdl 1pdl** Specifies a symbol 1pdl*, whose value is initially set to 2nil* by 2trace*. When the function is traced, a list of the current recursion level for the function, the function's name, and a list of arguments is consed onto the 1pdl* when the function is entered, and cdr'ed back off when the function is exited. The 1pdl* can be inspected from within a breakpoint, for example, and used to determine the very recent history of the function. This option can be used with or without printed trace output. Each function can be given its own pdl, or one pdl may serve several functions. 2:entryprint 1form** The 1form* is evaluated and the value is included in the trace message for calls to the function. You can give this option multiple times, and all the 1form*'s thus specified are evaluated and printed. 2\\* precedes the values to separate them from the arguments. 2:exitprint 1form** The 1form* is evaluated and the value is included in the trace message for returns from the function. You can give this option multiple times, and all the 1form*'s thus specified are evaluated and printed. 2\\* precedes the values to separate them from the returned values. 2:print 1form** The 1form* is evaluated and the value is included in the trace messages for both calls to and returns from the function. Equivalent to 2:exitprint* and 2:entryprint* at once. 2:entry 1list** This specifies a list of arbitrary forms whose values are to be printed along with the usual entry-trace. The list of resultant values, when printed, is preceded by 2\\* to separate it from the other information. 2:exit 1list** This is similar to 2entry*, but specifies expressions whose values are printed with the exit-trace. Again, the list of values printed is preceded by 2\\*. 2:arg :value :both nil* These specify which of the usual trace printouts should be enabled. If 2:arg* is specified, then on function entry the name of the function and the values of its arguments will be printed. If 2:value* is specified, then on function exit the returned value(s) of the function will be printed. If 2:both* is specified, both of these will be printed. If 2nil* is specified, neither will be printed. If none of these four options are specified the default is to 2:both*. If any further 1options* appear after one of these, they are not treated as options! Rather, they are considered to be arbitrary forms whose values are to be printed on entry and/or exit to the function, along with the normal trace information. The values printed will be preceded by a 2//*, and follow any values specified by 2:entry* or 2:exit*. Note that since these options ``swallow'' all following options, if one is given it should be the last option specified. .vindex arglist In the evaluation of the expression arguments to various 2trace* options such as 2:cond* and 2:break*, the value of 2arglist* is a list of the arguments given to the traced function. Thus 3(trace (foo :break (null (car arglist))))* would cause a break in 2foo* if and only if the first argument to 2foo* is 2nil*. If the 2:break* option is used, the variable 2arglist* is valid inside the break-loop. If you 2setq* 2arglist* before actual function execution, the arguments seen by the function will change. .vindex values In the evaluation of the expression arguments to various 2trace* options such as 2:cond* and 2:break* on exit from the traced function, the variable 2values* is bound to a list of the resulting values of the traced function. If the 2:exitbreak* option is used, the variables 2values* and 2arglist* are valid inside the break-loop. If you 2setq* 2values*, the values returned by the function will change. The trace specifications may be ``factored'', as explained above. For example, 3(trace ((foo bar) :break (bad-p arglist) :value))* 2is equivalent to* 3(trace (foo :break (bad-p arglist) :value)* 3 (bar :break (bad-p arglist) :value))* Since a list as a function name is interpreted as a list of functions, non-atomic function names (see 4(FUNCTIONS-1)Function Specs*) are specified as follows: 3(trace (:function (:method flavor :message) :break t))* 2trace* returns as its value a list of names of all functions it traced. If called with no arguments, as just 2(trace)*, it returns a list of all the functions currently being traced. If you attempt to trace a function already being traced, 2trace* calls 2untrace* before setting up the new trace. Tracing is implemented with encapsulation (see 4(FUNCTIONS-2)Encapsulations*), so if the function is redefined (e.g. with 2defun* or by loading it from a QFASL file) the tracing will be transferred from the old definition to the new definition. Tracing output is printed on the stream that is the value of 2*trace-output**. This is synonymous with 2*terminal-io** unless you change it. 3untrace* 1Special Form* Undoes the effects of 2trace* and restores functions to their normal, untraced state. 2untrace* accepts multiple specifications, e.g. 2(untrace foo quux fuphoo)*. Calling 2untrace* with no arguments will untrace all functions currently being traced. 3trace-compile-flag* 1Variable* If the value of 2trace-compile-flag* is non-2nil*, the functions created by 2trace* are compiled, allowing you to trace special forms such as 2cond* without interfering with the execution of the tracing functions. The default value of this flag is 2nil*. See also the function 2compile-encapsulations*, 4(COMPILER-1)How to Invoke the Compiler*. =Node: 4Breakon* =Text: 3BREAKON* The function 2breakon* allows you to request that the debugger be entered whenever a certain function is called. 3breakon* 1function-spec* &optional 1condition-form* Encapsulates the definition of 1function-spec* so that a trap-on-call occurs when it is called. This enters the debugger. A trap-on-exit will occur when the stack frame is exited. If 1condition-form* is non-2nil*, its value should be a form to be evaluated each time 1function-spec* is called. The trap occurs only if 1condition-form* evaluates to non-2nil*. Omitting the 1condition-form* is equivalent to supplying 2t*. If 2breakon* is called more than once for the same 1function-spec* and different 1condition-form*s, the trap occurs if any of the conditions are true. 2breakon* with no arguments returns a list of the functions that are broken on. Conditional breakons are useful for causing the trap to occur only in a certain stack group. This sometimes allows debugging of functions that are being used frequently in background processes. 3(breakon 'foo `(eq current-stack-group ',current-stack-group))* If you wish to trap on calls to 2foo* when called from the execution of 2bar*, you can use 2(si:function-active-p 'bar)* as the condition. If you want to trap only calls made directly from 2bar*, the thing to do is 3(breakon '(:within bar foo))* rather than a conditional breakon. To break only the 1n*'th time 2foo* is called, do 3(defvar i 1n*)* 3(breakon 'foo '(zerop (decf i)))* Another useful form of conditional breakon allows you to control trapping from the keyboard: 3(breakon 'foo '(tv:key-state :mode-lock))* The trap occurs only when the 2Mode-Lock* key is down. This key is not normally used for much else. With this technique, you can successfully trap on functions used by the debugger! 3unbreakon* 1function-spec* &optional 1conditional-form* Remove the 2breakon* set on 1function-spec*. If 1conditional-form* is specified, remove only that condition. Breakons with other conditions are not removed. With no arguments, 2unbreakon* removes all breakons from all functions. To cause the encapsulation which implements the breakon to be compiled, call 2compile-encapsulations* or set 2compile-encapsulations-flag* non-2nil*. See 4(COMPILER-1)How to Invoke the Compiler*. This may eliminate some of the problems that occur if you breakon a function such as 2prog* that is used by the evaluator. (A conditional to trap only in one stack group will help here also.) =Node: 4Advising a Function* =Text: 3ADVISING A FUNCTION* To advise a function is to tell it to do something extra in addition to its actual definition. It is done by means of the function 2advise*. The something extra is called a piece of advice, and it can be done before, after, or around the definition itself. The advice and the definition are independent, in that changing either one does not interfere with the other. Each function can be given any number of pieces of advice. Advising is fairly similar to tracing, but its purpose is different. Tracing is intended for temporary changes to a function to give the user information about when and how the function is called and when and with what value it returns. Advising is intended for semi-permanent changes to what a function actually does. The differences between tracing and advising are motivated by this difference in goals. Advice can be used for testing out a change to a function in a way that is easy to retract. In this case, you would call 2advise* from the terminal. It can also be used for customizing a function that is part of a program written by someone else. In this case you would be likely to put a call to 2advise* in one of your source files or your login init file (see 4(MISCELL-2)Logging In*), rather than modifying the other person's source code. Advising is implemented with encapsulation (see 4(FUNCTIONS-2)Encapsulations*), so if the function is redefined (e.g. with 2defun* or by loading it from a QFASL file) the advice will be transferred from the old definition to the new definition. 3advise* 1Macro* A function is advised by the special form 3(advise 1function* 1class* 1name* 1position** 3 1form1* 1form2*...)* None of this is evaluated. 1function* is the function to put the advice on. It is usually a symbol, but any function spec is allowed (see 4(FUNCTIONS-1)Function Specs*). The 1forms* are the advice; they get evaluated when the function is called. 1class* should be either 2:before*, 2:after*, or 2:around*, and says when to execute the advice (before, after, or around the execution of the definition of the function). The meaning of 2:around* advice is explained a couple of sections below. 1name* is used to keep track of multiple pieces of advice on the same function. 1name* is an arbitrary symbol that is remembered as the name of this particular piece of advice. If you have no name in mind, use 2nil*; then we say the piece of advice is anonymous. A given function and class can have any number of pieces of anonymous advice, but it can have only one piece of named advice for any one name. If you try to define a second one, it replaces the first. Advice for testing purposes is usually anonymous. Advice used for customizing someone else's program should usually be named so that multiple customizations to one function have separate names. Then, if you reload a customization that is already loaded, it does not get put on twice. 1position* says where to put this piece of advice in relation to others of the same class already present on the same function. If 1position* is 1nil*, the new advice goes in the default position: it usually goes at the beginning (where it is executed before the other advice), but if it is replacing another piece of advice with the same name, it goes in the same place that the old piece of advice was in. If you wish to specify the position, 1position* can be the numerical index of which existing piece of advice to insert this one before. Zero means at the beginning; a very large number means at the end. Or, 1position* can be the name of an existing piece of advice of the same class on the same function; the new advice is inserted before that one. 1For example,* 3(advise factorial :before negative-arg-check nil* 3 (if (minusp (first arglist))* 3 (ferror nil "factorial of negative argument")))* This modifies the (hypothetical) factorial function so that if it is called with a negative argument it signals an error instead of running forever. 2advise* with no arguments returns a list of advised functions. 3unadvise* 1Macro* 3(unadvise 1function* 1class* 1position*)* removes pieces of advice. None of its arguments are evaluated. 1function* and 1class* have the same meaning as they do in the function 2advise*. 1position* specifies which piece of advice to remove. It can be the numeric index (zero means the first one) or it can be the name of the piece of advice. If some of the arguments are missing or 2nil*, all pieces of advice which match the non-2nil* arguments are removed. Thus, if 1function* is missing or 2nil*, all advice on all functions which match the specified 1class* and 1position* are removed. If 1position* is missing or 2nil*, then all advice of the specified class on the specified function is removed. If only 1function* is non-2nil*, all advice on that function is removed. The following are the primitive functions for adding and removing advice. Unlike the above special forms, these are functions and can be conveniently used by programs. 2advise* and 2unadvise* are actually macros that expand into calls to these two. 3si:advise-1* 1function* 1class* 1name* 1position* 1forms* Adds advice. The arguments have the same meaning as in 2advise*. Note that the 1forms* argument is 1not* a 2&rest* argument. 3si:unadvise-1* &optional 1function* 1class* 1position* Removes advice. If 1function* or 1class* or 1position* is 2nil* or unspecified, advice is removed from all functions or all classes of advice or advice at all positions are removed. You can find out manually what advice a function has with 2grindef*, which grinds the advice on the function as forms that are calls to 2advise*. These are in addition to the definition of the function. To cause the advice to be compiled, call 2compile-encapsulations* or set 2compile-encapsulations-flag* non-2nil*. See 4(COMPILER-1)How to Invoke the Compiler*. =Node: 4Designing the Advice* =Text: 3DESIGNING THE ADVICE* For advice to interact usefully with the definition and intended purpose of the function, it must be able to interface to the data flow and control flow through the function. We provide conventions for doing this. The list of the arguments to the function can be found in the variable 2arglist*. 2:before* advice can replace this list, or an element of it, to change the arguments passed to the definition itself. If you replace an element, it is wise to copy the whole list first with 3(setq arglist (copylist arglist))* After the function's definition has been executed, the list of the values it returned can be found in the variable 2values*. 2:after* advice can set this variable or replace its elements to cause different values to be returned. All the advice is executed within a 2block nil* so any piece of advice can exit the entire function with 2return*. The arguments of the 2return* are returned as the values of the function and no further advice is executed. If a piece of 2:before* advice does this then the function's definition is not even called. =Node: 4:around Advice* =Text: 3:AROUND ADVICE* A piece of 2:before* or 2:after* advice is executed entirely before or entirely after the definition of the function. 2:around* advice is wrapped around the definition; that is, the call to the original definition of the function is done at a specified place inside the piece of 2:around* advice. You specify where by putting the symbol 2:do-it* in that place. For example, 2(+ 5 :do-it)* as a piece of 2:around* advice would add 25* to the value returned by the function. This could also be done by 2(setq values (list (+ 5 (car values))))* as 2:after* advice. When there is more than one piece of 2:around* advice, the pieces are stored in a sequence just like 2:before* and 2:after* advice. Then, the first piece of advice in the sequence is the one started first. The second piece is substituted for 2:do-it* in the first one. The third one is substituted for 2:do-it* in the second one. The original definition is substituted for 2:do-it* in the last piece of advice. 2:around* advice can access 2arglist*, but 2values* is not set up until the outermost 2:around* advice returns. At that time, it is set to the value returned by the 2:around* advice. It is reasonable for the advice to receive the values of the 2:do-it* (e.g. with 2multiple-value-list*) and fool with them before returning them (e.g. with 2values-list*). 2:around* advice can 2return* from the 2block* at any time, whether the original definition has been executed yet or not. It can also override the original definition by failing to contain 2:do-it*. Containing two instances of 2:do-it* may be useful under peculiar circumstances. If you are careless, the original definition may be called twice, but something like 3(if (foo) (+ 5 :do-it) (* 2 :do-it))* will work reasonably. =Node: 4Advising One Function Within Another* =Text: 3ADVISING ONE FUNCTION WITHIN ANOTHER* It is possible to advise the function 2foo* only for when it is called directly from a specific other function 2bar*. You do this by advising the function specifier 2(:within bar foo)*. That works by finding all occurrences of 2foo* in the definition of 2bar* and replacing them with 2#:altered-foo-within-bar*. (Note that this is an uninterned symbol.) This can be done even if 2bar*'s definition is compiled code. The symbol 2#:altered-foo-within-bar* starts off with the symbol 2foo* as its definition; then the symbol 2#:altered-foo-within-bar*, rather than 2foo* itself, is advised. The system remembers that 2foo* has been replaced inside 2bar*, so that if you change the definition of 2bar*, or advise it, then the replacement is propagated to the new definition or to the advice. If you remove all the advice on 2(:within bar foo)*, so that its definition becomes the symbol 2foo* again, then the replacement is unmade and everything returns to its original state. 2(grindef bar)* prints 2foo* where it originally appeared, rather than 2#:altered-foo-within-bar*, so the replacement is not seen. Instead, 2grindef* prints calls to 2advise* to describe all the advice that has been put on 2foo* or anything else within 2bar*. An alternate way of putting on this sort of advice is to use 2advise-within*. 3advise-within* 1Macro* 3(advise-within 1within-function* 1function-to-advise** 3 1class* 1name* 1position** 3 1forms...*)* advises 1function-to-advise* only when called directly from the function 1within-function*. The other arguments mean the same thing as with 2advise*. None of them are evaluated. To remove advice from 2(:within bar foo)*, you can use 2unadvise* on that function specifier. Alternatively, you can use 2unadvise-within*. 3unadvise-within* 1Macro* 3(unadvise-within 1within-function* 1function-to-advise* 1class* 1position*)* removes advice that has been placed on 2(:within 1within-function* 1function-to-advise*)*. Any of the four arguments may be missing or 2nil*; then that argument is unconstrained. All advice matching whichever arguments are non-2nil* is removed. For example, 2(unadvise-within foo nil* 2:before)* removes all 2:before*-advice from anything within 2foo*. 2(unadvise-within)* removes all advice placed on anything within anything. By contrast, 2(unadvise)* removes all advice, including advice placed on a function for all callers. Advice placed on a function not within another specific function is never removed by 2unadvise-within*. The function versions of 2advise-within* and 2unadvise-within* are called 2si:advise-within-1* and 2si:unadvise-within-1*. 2advise-within* and 2unadvise-within* are macros that expand into calls to the other two.