A JIT compiler observes that a function is always called with integer arguments and generates a specialized integer-only version. What must the JIT include to handle the case when the function is later called with a float?
AA compile-time type checker that prevents the float call
BA guard that checks the type assumption at runtime and falls back if violated
CA second pass of the AOT compiler to handle edge cases
DNothing — the specialized version will automatically handle floats correctly
Speculative optimization requires guards — runtime checks that verify the assumed conditions still hold. If a float is passed (violating the integer assumption), the guard triggers and the JIT falls back to a slower generic path or recompiles. Without guards, specialization would produce incorrect results. A JIT cannot use compile-time type checking (option A) because type information only exists at runtime, and AOT is not invoked at runtime (option C).
Question 2 Multiple Choice
Why can a JIT-compiled language sometimes outperform ahead-of-time compiled C code for specific workloads?
AJIT compilers use faster hardware than AOT compilers
BJIT compilers skip register allocation to save compilation time
CJIT can generate code specialized to the actual runtime types and hot paths, which AOT cannot know in advance
DJIT-compiled languages are always more efficient because they eliminate all dead code
AOT compilers must generate conservative code that handles all possible inputs and paths — they cannot assume any runtime conditions. A JIT observes which paths are actually taken and what types are actually used, then generates code optimized for exactly those cases. This specialization can outperform AOT-compiled code for specific workloads. However, this advantage disappears when speculative assumptions are violated, and JITs pay overhead for profiling and compilation — so JIT does not uniformly outperform AOT.
Question 3 True / False
A JIT compiler starts by executing code in an interpreter before compiling anything, which makes programs initially slower than AOT-compiled equivalents.
TTrue
FFalse
Answer: True
This is a real tradeoff — interpretation is slower than compiled execution. Tiered JIT systems accept this startup penalty: code runs interpreted first (zero compilation cost), gets baseline-compiled when it warms up, and receives full optimization only when identified as hot. For long-running programs, the eventual compiled code more than compensates for the startup overhead. For short-running programs, JIT-compiled code may be slower overall than AOT-compiled code.
Question 4 True / False
JIT compilation is essentially the same as ahead-of-time compilation, just performed later in the process.
TTrue
FFalse
Answer: False
JIT compilation is fundamentally different from AOT because it has access to runtime information that AOT never has: profiling data on which code is hot, actual runtime types, observed branching patterns, and memory layout information. This allows JIT to perform speculative optimizations (inlining, type specialization) that are unsound for AOT. AOT must generate code correct for all possible inputs; JIT can speculate on observed behavior and add guards to catch violations. The timing difference is secondary — the information advantage is what makes JIT qualitatively different.
Question 5 Short Answer
Explain why a JIT compiler needs to interact with the garbage collector, and what could go wrong if it did not.
Think about your answer, then reveal below.
Model answer: JIT-compiled code generates machine instructions that access object fields at specific byte offsets based on observed object structure. A compacting garbage collector may move objects in memory. If the GC does not inform the JIT about these moves, the compiled code will access stale memory addresses, causing crashes or incorrect results. The GC must know which memory locations in compiled code contain object references (via stack maps at safe points) so it can update them when objects are relocated.
This GC-JIT cooperation is a major source of architectural complexity in JIT systems. Safe points in compiled code mark places where the GC can pause execution, and the JIT must emit stack maps identifying which registers and stack slots hold live object references. This tight coupling between runtime compilation and memory management is part of what makes JIT systems architecturally complex compared to simple AOT compilers.