Master the fundamental concepts of jvm internals through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksThe JVM starts in the interpreter, then promotes hot methods through C1 (fast, lightly optimized) to C2 (aggressive optimizing). Tiered compilation balances startup time against peak throughput.
Typical progression:
Method invocation counters and back-edge counters trigger compilation. OSR (on-stack replacement) compiles loops inside long-running methods without waiting for the next entry.
For example, a server loop may run interpreted for thousands of iterations, hit C1, then C2 with inlined callees and escape analysis.
Flags like \`-XX:+TieredCompilation\` control the policy on modern JDKs.
Compile thresholds exist because compiling everything at startup would slow launch unbearably. Server workloads benefit from higher thresholds; interactive apps sometimes lower them for snappier first interactions.
This exercise asks you to document the interpret-to-C1-to-C2 pipeline. You will explain what triggers each tier and why cold code stays interpreted while hot paths get native code.
You will use the same mental model here when reading production interpreter source later in the track. Sketch one concrete input on paper, predict the outcome, then confirm with code. That discipline catches logic errors early and makes debugging far faster when you extend the implementation in follow-on tasks.
Simulate HotSpot's tiered compilation policy. Methods start in the interpreter (level 0), get compiled by C1 with profiling (level 3) once warm, or by C1 without profiling (level 1) if trivial, and by C2 (level 4) once hot. Long-running loops trigger OSR (on-stack replacement) compiles. An uncommon trap in C2 code deoptimizes the method back to the interpreter, and a method that traps too often is barred from C2. Print a -XX:+PrintCompilation-style log.
# starts a comment.
cLoading…
Each method has counters inv and back, which reset to 0 whenever it is compiled at a new level (not for OSR). A global tick increases by 1 per invocation and per back-edge.
inv >= 200, or inv >= 100 && inv + back >= 2000, compile at level 1 if trivial, else at level 3;inv >= 5000, or inv >= 1000 && inv + back >= 15000, compile at level 4.back >= 10000 and no OSR code at level ≥ 3: OSR compile at level 3;back >= 40000 and no OSR code at level 4: OSR compile at level 4.trap REASON: ignored, NAME is not running C2 code):
uncommon trap in NAME: REASON -> deoptimize;NAME: too many traps, not compilable at level 4, and the method never goes past level 3 again.Log lines use %8ld %5d %c %d NAME[ @ loop] (SIZE bytes)[ made not entrant]: the tick, the compile id, % for OSR (else a space), and the level.
cLoading…
NAME: level L DESC, invocations I, backedges B since then, traps T[, C2 disabled]. DESC is interpreter, C1 (no profiling), C1 (limited profiling), C1 (full profiling) or C2.method: NAME SIZE (1-65535 bytes), method X: already defined, method X: too many methods (16 max)call: NAME [COUNT 1-10000000] / loop: …call: unknown method X (likewise for loop and trap)trap: NAME REASONunknown command XInput:
cLoading…
Output:
cLoading…
Hidden tests cover OSR at both levels followed by a normal C2 compile, repeated traps that disable C2, traps on non-C2 code, and command errors.