JIT
Subverge compiles quotes to native x86-64 code while it runs. This page shows you how to look at the compiler's work, what it generates and when its output is thrown away.
Contents
Usage
A quote is compiled the second time it runs, so you do not have to ask for it (it just happens, enjoy).
jit status
jit-off jit-on toggle
'fib compile compile now, gives address and length
addr n dis disassemble n instructions
addr len disr disassemble a region
'fib xray source and machine code together
bench time a quote with the JIT off, then on
The full list of words is jit jit-on jit-off compile addr dis disr jitdis xray bench. 'name compile returns the address and length of the native code, 'name xray shows it beside the source, and bench times a quote with the JIT off and then on. On a recursive fib it reports 85 ticks interpreted and 3 compiled (yes, that fucking fast).
Check the tour for screenshots of xray and bench.
Design
The JIT produces call-threaded x86-64. These registers are fixed while compiled code runs (this is the nerdy part):
| Register | Holds |
|---|---|
rbx |
omega state |
r12 |
top of stack pointer |
r13 |
stack base |
r14 |
depth |
r15 |
saved local count |
rbp |
frame |
These words are inlined, each with a type check and a fallback to the built-in: + - * & | xor, the comparisons, and dup over drop swap nip not neg. The literal-quote forms of if when unless times for while become native jumps. Everything else is a call back into the interpreter.
That is why fib speeds up so much, from 85 ticks to 3, while a loop that is mostly arithmetic speeds up less.
Invalidation
Compiled code is guarded by jit_version, which is increased when a definition shadows a built-in or when root is rebuilt. Stale code cannot be freed immediately, because another tab may be executing it. It goes onto a 512-entry dead list, and an atomic jit_running counter shows when nothing anywhere is inside compiled code. The list is swept only at that point.
A root rebuild retires the code of the units that it replaced. Your quote is compiled again the next time it runs twice.
Disassembler
xray uses kernel/dis.c, a small x86-64 disassembler that is checked against objdump.