Sscalascript.dev

Compile-time at scale — findings (2026-06-15)

Why

Every compile/codegen benchmark (CompilerBench, CrossBackendBench) used 6-line inputs. The recent codegen-time win (jvmgen-codegen-time, −94%) was measured on those tiny programs. So compile-time on a real-size module — where an O(n²) frontend/codegen pass would actually bite — was unmeasured. This closes that gap.

Method

A synthetic large module: n arithmetic functions in a cross-referencing chain (fK calls fK-1 + fK-2) + t = n/20 case classes under a sealed trait with a pattern-matching dispatcher + a final block. Each stage timed independently as n grows: Parser.parse, Typer.typeCheck, JvmGen.generate, JsGen.generate (median of warmed runs, one quiet machine).

Results

N (defs)src KBparse mstype msjvmGen msjsGen ms
502.98.97.34.41.6
1005.19.09.57.72.7
2009.811.610.214.04.8
40019.911.612.021.89.4
8004017.921.745.620.1
16008337.942.395.949.9
3200170196.987.3
6400345464.7239.7

Scaling per 2× input (2.0 = linear, 4.0 = quadratic):

stageratio rangeverdict
parse1.7–2.0linear
type1.7–2.0linear
jvmGen2.1–2.4roughly linear, mild superlinear tail (~O(n^1.15))
jsGen1.8–2.8roughly linear, mild superlinear tail

Conclusion

The pipeline scales acceptably — no quadratic blowup anywhere. The frontend (parse + type) is linear; both codegen backends are roughly linear with a mild superlinear tail (~×2.1–2.4 per doubling, not ×4). Even a 6400-def / 345 KB single module — far larger than a typical module — compiles in <0.5 s (jvmGen ~465 ms, jsGen ~240 ms). jvmGen is ~2× jsGen in absolute terms (the per-def Scala- source emission is heavier than JS emission; the fixed per-call preamble cost was already removed by jvmgen-codegen-time).

No fix warranted. Chasing the mild superlinear tail at 6400-def scale would be low-value (the effect is mild and the absolute time is a sub-second one-time compile cost). If a future change introduces a real O(n²) pass, CompileScaleBench (added alongside this doc) will surface it.

Guard

runtime/backend/interpreter-bench/.../CompileScaleBench.scala — JMH bench compiling an ~800-def module through parse/type/jvmGen/jsGen, so large-program compile-time is part of standing bench coverage:

sbt "interpreterBench/Jmh/run .*CompileScaleBench.*"