Skip to content

How Lisp runs

EGCL balances startup cost against the value of optimizing frequently executed code. It does not require every function to pass through an optimizing compiler before the program can run.

Interpretation and compilation

The reader turns text into Lisp forms. Macro expansion and lowering turn supported forms into bytecode. Some forms use the tree-walking evaluator as a compatibility or bootstrap path. Bytecode executes in T0 while the runtime collects information about calls and loop back edges.

Tier Role
T0 Bytecode execution with low compilation cost
T1 Baseline native code for supported bytecode shapes
T2 Optimized native code using the SSA compiler pipeline

A function that cannot be compiled by a target backend can continue at a lower tier. Native support is target-specific; see the platform table. A function's semantics should not depend on whether it is interpreted or compiled.

A hot function is different from a hot loop

A function called repeatedly may have its entry point replaced by native code. A long-running loop may instead enter compiled code during the current call. That transition is on-stack replacement, or OSR. EGCL transfers live values to the compiled loop's expected locations and continues the same computation.

This distinction matters when observing performance. A function can still be reported as T0 by function-tier or disassemble while its active loop runs native code through OSR. An installed function tier is not a trace of every instruction executed during a call.

Why optimized code can exit

T2 may optimize under assumptions, such as an operand being a fixnum. Guards check those assumptions. When a guard fails, deoptimization reconstructs the state needed to resume less-specialized execution. It must preserve effects already performed, values still live, and the correct resumption position.

The same boundary interacts with the garbage collector: objects may move, so native registers and stack locations must agree with the collector's root metadata. The runtime architecture explains where these responsibilities live in the source tree.