Compiled code usually accesses variables in top-level first-class environments via variable caches. Each compiled procedure has a set of variable caches for the top-level variables that it uses. There are three kinds of variable cache—read caches for getting the value of a variable (referencing the variable), write caches for changing the value, and execute caches for calling the procedure assigned to that variable.
Sometimes the variable caches contain special objects, called reference traps, that indicate that the operation cannot proceed normally and must either be completed by the system (in order to keep the caches coherent) or must signal an error. For example, the assignment
(set! newline my-better-newline)
will cause the system to go to each compiled procedure that calls
newline and update its execute cache to call the new procedure.
Obviously you want to avoid updating hundreds of execute caches in a
critical loop. Using
fluid-let to temporarily redefine a
procedure has the same inefficiency (but twice!), which is a great
reason to use
To behave correctly in all situations, each variable reference or assignment must check for the reference traps.
Sometimes you can prove that the variable (a) will always be bound, (b) will never be unassigned, and (c) there will never be any compiled calls to that variable. The compiler can’t prove this because it assumes that other independently compiled files might be loaded that invalidate these assumptions. If you know that these conditions hold, the following declarations can speed up and reduce the size of a program that uses global variables.
This declaration tells the compiler that it need not check for reference-trap objects when referring to the given variables. If any of the variables is unbound or unassigned then a variable reference will yield a reference-trap object rather than signaling an error. This declaration is relatively safe: the worst that can happen is that a reference-trap object finds its way into a data structure (e.g. a list) or into interpreted code, in which case it will probably cause some ‘unrelated’ variable to mysteriously become unbound or unassigned.
This declaration tells the compiler that it need not check for reference-trap objects when assigning to the given variables. An assignment to a variable that ignores assignment traps can cause a great deal of trouble. If there is a compiled procedure call anywhere in the system to this variable, the execute caches will not be updated, causing an inconsistency between the value used for the procedure call and the value seen by reading the variable. This mischief is compounded by the fact that the assignment can cause other assignments that were compiled with checks to behave this way too.
The variables are specified with expressions from the following set language:
All of the explicitly listed names.
These expressions name sets of variables.
all is the set of all
none is the empty set,
free is all of the
variables bound outside the current block,
bound is all of the
variables bound in the current block and
assigned is all of the
variables for which there exists an assignment (i.e.
For example, to ignore reference traps on all the variables except x, y and any variable that is assigned to
(declare (ignore-reference-traps (difference all (union assigned (set x y)))))