seniorRuby
How does CRuby ensure correctness when JIT (YJIT) compiled code interacts with the interpreter?
Updated May 17, 2026
Short answer
CRuby enforces correctness by using guards, deoptimization (fallback), and shared VM state between YJIT and interpreter.
Deep explanation
YJIT does not replace the interpreter; it generates machine code for hot basic blocks with embedded guards (type checks, class checks, method version checks). If any assumption becomes invalid (e.g., method redefinition or object shape change), execution jumps back to the interpreter via deoptimization. Both interpreter and JIT share the same VM state (stack, heap, GVL), ensuring semantic consistency. This design prioritizes correctness over aggressive optimization.
Real-world example
Rails production servers dynamically switch between interpreted and JIT paths under load.
Common mistakes
- Assuming JIT replaces interpreter execution entirely.
Follow-up questions
- What is deoptimization in Ruby?
- What are guards?