SCUA runs on an interpreter by default. That's fast to start and fine
for most scripts. When a script spends its time in hot loops — physics
and simulation, math over vectors and matrices, walking large tables —
an optional JIT (just-in-time compiler) turns those loops into native
code so they run much faster. It's off by default and you opt in with
--jit=on. The output is exactly the same either way, so you
can turn it on and off freely.
#Turn it on
Run any script with --jit=on:
fn walk(steps)
let p = vec2(0.0, 0.0)
let v = vec2(1.0, 0.5)
for i in 0:steps do
p = p + v
end
return p
end
let p = walk(1000000)
print(`{p.x}, {p.y}`)
$ scua --jit=on walk.scua
1000000, 500000
Without the flag the same file runs on the interpreter and prints the
same thing. --jit=on doesn't change what the program does;
it compiles the loop that runs a million times down to native code once
it's clear the loop is hot, and runs the rest of the way from there.
#What gets faster
The JIT pays off where the same code runs many times:
- Hot loops. A loop body that runs thousands or millions of times is the case it's built for.
- Math-heavy code. Vector, quaternion, and matrix work (the math types) benefits most.
- Table-heavy code. Repeated access to string-keyed tables gets faster too.
Code that runs briefly gains little, because nothing runs long enough
to be worth compiling: startup, one-shot scripts, and glue that calls
out to the host and waits. The JIT isn't free — compiling takes a moment
— so on a short script --jit=on can even cost a little.
Reach for it when a script is doing real, repeated computation.
#The output never changes
The JIT is a speed tier, not a different language. A program produces the same results with it on or off, so it's safe to toggle: develop with it off, turn it on for a heavy run, and compare. (The examples in this manual are checked both ways in CI, on the interpreter and with the JIT forced on, and required to match.)
#Which platforms it runs on
The JIT compiles native code on ARM64 (Apple Silicon and ARM Linux)
and on x86-64 (macOS and Linux). On any other platform,
--jit=on is accepted and ignored, and the script runs on
the interpreter with the same output. That means you can safely leave
the flag in a launch command: you get native code where the platform
supports it and the interpreter everywhere else, with no change to what
the program prints.
#See it working
Add --jit-stats to print a one-line summary to stderr
when the run ends. (--jit-stats turns the JIT on by itself,
so you don't need --jit=on as well.)
$ scua --jit-stats walk.scua
1000000, 500000
[jit] mode=on compiled=2 native-entries=6 deopts=4 ...
compiled= is how many functions it compiled and
native-entries= how many times it ran native code; a
deopt is a fall back to the interpreter. The exact numbers
are diagnostics and vary between runs and releases. What you're looking
for is compiled= above zero with native entries to match —
that's your hot loop running as native code. All zeros means nothing ran
long enough to compile, which is your cue that the JIT has nothing to do
for this script.
#The other modes
--jit=off is the explicit form of the default
(interpreter only). --jit=always compiles eagerly instead
of waiting for a loop to warm up; it's slower to start and mainly there
for testing that the JIT and the interpreter agree. For everyday use,
--jit=on is the one you want.
See the command-line reference for the full flag surface.