JIT Tiered — Compilación en Múltiples Niveles

Archivo: src/jit_tiered.rs (347 líneas)

¿Por qué existe?

Implementa el sistema de compilación en niveles (tiered JIT) de Forja: en lugar de compilar todo siempre, las funciones comienzan interpretadas y solo se compilan a código nativo cuando demuestran ser calientes (hot). Esto amortiza el costo de compilación concentrándolo en las funciones y loops que más se ejecutan.

Tier 0: ForjaFast VM (interpreter)
  ↓ hotness counter
Tier 1: JIT template-based (compilación rápida, ~1ms)
  ↓ hotness counter
Tier 2: JIT optimizado (SSA, register alloc, SIMD) [futuro]

Tiers

TierDescripción
Tier::InterpretIntérprete de la ForjaFast VM — tier inicial de toda función
Tier::JitSimpleJIT template-based: compilación rápida (~1 ms) sin optimizaciones pesadas
Tier::JitOptimizedJIT optimizado (SSA, register allocation, SIMD) — planeado como futuro

Tier::next() modela la cadena: Interpret → JitSimple → JitOptimized → None.

Contadores de hotness

ComponenteDescripción
HotnessThresholdsUmbrales configurables: interpret_to_jit_simple (default 1 000 ejecuciones), jit_simple_to_optimized (default 100 000), osr_loop_iterations (default 10 000 iteraciones)
FunctionStateEstado por función: tier actual, call_count, compiled_code (Option<CompiledCode>) y deopt_frame (Option<DeoptFrame>)
FunctionState::tick()Incrementa el contador y retorna ShouldCompile: No, o Yes(Tier) cuando supera el umbral del tier actual
ShouldCompileResultado del tick: No | Yes(Tier)
CompiledCodeCódigo compilado: code_ptr a memoria ejecutable, code_size y tier. unsafe impl Send/Sync (inmutable una vez creado)

OSR y Deoptimización

MecanismoDescripción
OSR (On-Stack Replacement)on_loop_iteration(func_id, loop_pc) cuenta iteraciones por loop (clave "func_id:loop_pc") y, al superar osr_loop_iterations, permite compilar el loop a Tier 1 mientras está ejecutándose
DeoptFrameSnapshot del estado del intérprete para hacer bailout: pc, base_ptr, locals, stack y from_tier
deoptimize(name, frame)Cuando una asunción de tipo falla, devuelve la función a Tier::Interpret, elimina el código compilado y guarda el frame

TieredJit — Orquestador

MétodoDescripción
new() / with_thresholds(t)Constructores (default y con umbrales personalizados)
register_function(name)Registra una función con estado inicial Interpret
on_function_call(name) -> ShouldCompileNotifica una ejecución y consulta si debe compilarse
on_loop_iteration(func_id, loop_pc) -> boolContador OSR por loop; true si supera el umbral
mark_compiled(name, tier, code)Marca la función como compilada y actualiza las estadísticas
deoptimize(name, frame)Bailout al intérprete
tier_of(name) -> TierTier actual de la función (default Interpret)
stats() -> &JitStatsEstadísticas: compilaciones por tier, OSR completados, deopts y tiempo de compilación (µs)

Conexión con jit.rs y jit_engine.rs

Punto de integraciónDescripción
NativeJIT (jit.rs:439)Contiene el campo tiered: Option<TieredJit> y expone wrappers: on_function_call(), register_function(), mark_compiled(), deoptimize() (que además limpia el cache compiled), on_loop_iteration(), tier_of(), set_tiered(enabled) y tier_stats()
JitOrchestrator (jit_engine.rs:742)Mantiene un TieredJit propio. En ejecutar(), si es_jiteable(bytecode) aplica la cadena de optimización (optimizar_indicesloop_unrollingfusionar_opcodesespecializar_bytecode) y luego, para cada FunctionDef, registra la función (register_function) y hace tick por cada Call (on_function_call) para decidir compilación; si el JIT nativo falla, ejecuta con ForjaFast como fallback
PGOJitOrchestrator integra crate::pgo: los candidatos tier-2 del perfil fuerzan un tick, y loops calientes ajustan el factor de unrolling (8x vs 4x)
Estado actual: el motor de hotness, OSR, deoptimización y estadísticas está implementado y testeado (umbrales, cadena de tiers, custom thresholds). El código real de JitOptimized (SSA/SIMD) está marcado como trabajo futuro.