Virtual Machine

Marwood has a stack based virtual machine represented by the Vm object. Each Vm represents a full scheme runtime environment.

Scheme expressions evaluated on the VM are compiled into byte code represented by [op codes], which are evaluated by the VM.

#[derive(Debug)]
pub struct Vm {
    /// The heap and global environment
    heap: Heap,
    globenv: GlobalEnvironment,

    /// The current program stack
    stack: Stack,

    /// Registers
    acc: VCell,
    ep: usize,
    ip: (usize, usize),
    bp: usize,

    /// System Interface (display, write, etc).
    sys: Box<dyn SystemInterface>,
}

The Vm object provides an eval interface for evaluating scheme expressions, and is the main interface for the console and web repl:

fn eval(&mut self, cell: &Cell) -> Result<Cell, Error>

VM Components

The Vm is composed of these high-level components, which are explored later in this chapter:

Registers

The Vm has a handful of registers that are used to maintain currently running program state:

RegisterDescription
%accAccumulator
%ipInstruction Pointer
%bpFrame Base Pointer
%spStack Pointer
%epEnvironment Pointer

The %acc (or accumulator) register contains the result of any Vm instruction that produces a result. The %acc register is also used by procedures to store the result of procedure application. For example, the procedure (+ 10 10) would result in %acc containing the result 20.

The %ip register contains a tuple that points to the currently running block of bytecode, and offset in the bytecode of the next instruction to be executed.

The %bp, %sp and %ep registers maintain state of Marwood's stack and call frame state and are discussed in detail in the procedure application section.

Op Codes

Marwood's instruction set is built specifically for executing scheme. It's not a general purpose virtual machine.

The MOV instruction is used to move values between Marwood's registers, stack, global and lexical environments.

The CALL, CLOSURE, ENTER, RET, TCALL, and VARARG instructions support procedure application.

The JMP and JNT provide branching support for the compiler to support the scheme if primitive.

The CONS and VPUSH instructions are instructions used to build lists or vectors at runtime, and are primarily used to support the quasiquote language feature.

The HALT instruction stops the virtual machine, returning the contents of the %acc register as the result to eval.

OpcodeDescription
CALL %accGiven the arguments for the procedure in %acc have been pushed on the stack, jump to the procedure in %acc.
CLOSURE %accCreate a lexical environment as a result of evaluating a (lambda ...) expression.
CONSPerforms the cons operation on the first two values of the stack, storing the resulting pair in %acc
ENTERSetup the currently executing procedure's stack frame
HALTHalt program, returning the result contained within ACC
JNT <OFFSET>Set %ip to OFFSET if %acc is #f
JMP <OFFSET>Set %ip to OFFSET
MOV <SRC> <DEST>Move the value from SRC into DEST
PUSHPush the value in ACC on to the stack
RETReturn from a procedure entered via CALL
TCALL %accIdentical to a CALL instruction, except that a tail optimizing CALL is performed.
VPUSHPush the value in %acc onto the vector at the top of the stack, storing the resulting vector in %acc