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.
The first argument of calls to these hooks is the frame in question. See Frames. Some hooks may call their procedures with more arguments. 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))
All of these functions implicitly act on the VM for the current thread only.
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 fires with a variable number of arguments, corresponding to the values that the frame returns to its continuation.
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.
Like the pop-continuation hook, this hook fires with a variable number of arguments, corresponding to the values that returned to the continuation.
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.