Everything that runs in Guile runs on its virtual machine, a C program that defines a number of operations that Scheme programs can perform.
Note that there are multiple VM “engines” for Guile. Only some of them have support for hooks compiled in. Normally the deal is that you get hooks if you are running interactively, and otherwise they are disabled, as they do have some overhead (about 10 or 20 percent).
To ensure that you are running with hooks, pass
--debug to Guile
when running your program, or otherwise use the
set-vm-engine! procedures to ensure that you are running in a VM
To digress, Guile’s VM has 6 different hooks (see Hooks) that can be fired at different times, which may be accessed with the following procedures.
All hooks are called with one argument, the frame in question. See Frames. Since these hooks may be fired very frequently, Guile does a terrible thing: it allocates the frames on the C stack instead of the garbage-collected heap.
The upshot here is that the frames are only valid within the dynamic extent of the call to the hook. If a hook procedure keeps a reference to the frame outside the extent of the hook, bad things will happen.
The interface to hooks is provided by the
(system vm vm) module:
(use-modules (system vm vm))
The result of calling
the-vm is usually passed as the vm
argument to all of these procedures.
The hook that will be fired before an instruction is retired (and executed).
The hook that will be fired after preparing a new frame. Fires just before applying a procedure in a non-tail context, just before the corresponding apply-hook.
The hook that will be fired before returning from a frame.
This hook is a bit trickier than the rest, in that there is a particular interpretation of the values on the stack. Specifically, the top value on the stack is the number of values being returned, and the next n values are the actual values being returned, with the last value highest on the stack.
The hook that will be fired before a procedure is applied. The frame’s procedure will have already been set to the new procedure.
Note that procedure application is somewhat orthogonal to continuation pushes and pops. A non-tail call to a procedure will result first in a firing of the push-continuation hook, then this application hook, whereas a tail call will run without having fired a push-continuation hook.
The hook that will be called after aborting to a
prompt. See Prompts. The stack will be in the same state as for
The hook that will be called after restoring an undelimited continuation. Unfortunately it’s not currently possible to introspect on the values that were given to the continuation.
These hooks do impose a performance penalty, if they are on. Obviously,
vm-next-hook has quite an impact, performance-wise. Therefore
Guile exposes a single, heavy-handed knob to turn hooks on or off, the
VM trace level. If the trace level is positive, hooks run;
otherwise they don’t.
For convenience, when the VM fires a hook, it does so with the trap level temporarily set to 0. That way the hooks don’t fire while you’re handling a hook. The trace level is restored to whatever it was once the hook procedure finishes.
Retrieve the “trace level” of the VM. If positive, the trace hooks associated with vm will be run. The initial trace level is 0.
Set the “trace level” of the VM.
See A Virtual Machine for Guile, for more information on Guile’s virtual machine.