Warning: This is the manual of the legacy Guile 2.0 series. You may want to read the manual of the current stable series instead.
Next: Variables and the VM, Previous: VM Concepts, Up: A Virtual Machine for Guile [Contents][Index]
While not strictly necessary to understand how to work with the VM, it is instructive and sometimes entertaining to consider the structure of the VM stack.
Logically speaking, a VM stack is composed of “frames”. Each frame corresponds to the application of one compiled procedure, and contains storage space for arguments, local variables, intermediate values, and some bookkeeping information (such as what to do after the frame computes its value).
While the compiler is free to do whatever it wants to, as long as the semantics of a computation are preserved, in practice every time you call a function, a new frame is created. (The notable exception of course is the tail call case, see Tail Calls.)
Within a frame, you have the data associated with the function application itself, which is of a fixed size, and the stack space for intermediate values. Sometimes only the former is referred to as the “frame”, and the latter is the “stack”, although all pending application frames can have some intermediate computations interleaved on the stack.
The structure of the fixed part of an application frame is as follows:
Stack | ... | | Intermed. val. 0 | <- fp + bp->nargs + bp->nlocs = SCM_FRAME_UPPER_ADDRESS (fp) +==================+ | Local variable 1 | | Local variable 0 | <- fp + bp->nargs | Argument 1 | | Argument 0 | <- fp | Program | <- fp - 1 +------------------+ | Return address | | MV return address| | Dynamic link | <- fp - 4 = SCM_FRAME_DATA_ADDRESS (fp) = SCM_FRAME_LOWER_ADDRESS (fp) +==================+ | |
In the above drawing, the stack grows upward. The intermediate values
stored in the application of this frame are stored above
SCM_FRAME_UPPER_ADDRESS (fp)
. bp
refers to the
struct scm_objcode
data associated with the program at
fp - 1
. nargs
and nlocs
are properties of the
compiled procedure, which will be discussed later.
The individual fields of the frame are as follows:
The ip
that was in effect before this program was applied. When
we return from this activation frame, we will jump back to this
ip
.
The ip
to return to if this application returns multiple
values. For continuations that only accept one value, this value will
be NULL
; for others, it will be an ip
that points to a
multiple-value return address in the calling code. That code will
expect the top value on the stack to be an integer—the number of
values being returned—and that below that integer there are the
values being returned.
This is the fp
in effect before this program was applied. In
effect, this and the return address are the registers that are always
“saved”. The dynamic link links the current frame to the previous
frame; computing a stack trace involves traversing these frames.
Lambda-local variables that are all allocated as part of the frame. This makes access to variables very cheap.
The calling convention of the VM requires arguments of a function application to be pushed on the stack, and here they are. References to arguments dispatch to these locations on the stack.
This is the program being applied. For more information on how programs are implemented, See VM Programs.
Next: Variables and the VM, Previous: VM Concepts, Up: A Virtual Machine for Guile [Contents][Index]