SCUA

How-to

Make scripts run faster with the JIT

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.