use std::collections::HashMap;
pub const OSR_INTERP_TO_BASELINE: u32 = 10;
pub const OSR_BASELINE_TO_MAGLEV: u32 = 100;
pub const OSR_MAGLEV_TO_TURBOFAN: u32 = 1_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ExecutionTier {
Interpreter,
Baseline,
Maglev,
Turbofan,
}
impl ExecutionTier {
pub fn next(self) -> Option<Self> {
match self {
Self::Interpreter => Some(Self::Baseline),
Self::Baseline => Some(Self::Maglev),
Self::Maglev => Some(Self::Turbofan),
Self::Turbofan => None,
}
}
pub fn osr_threshold(self) -> u32 {
match self {
Self::Interpreter => OSR_INTERP_TO_BASELINE,
Self::Baseline => OSR_BASELINE_TO_MAGLEV,
Self::Maglev => OSR_MAGLEV_TO_TURBOFAN,
Self::Turbofan => u32::MAX,
}
}
}
#[derive(Debug, Clone)]
pub struct OsrFrameState {
pub loop_header_offset: u32,
pub function_id: u64,
pub register_values: Vec<i64>,
pub accumulator: i64,
pub local_count: u32,
pub source_tier: ExecutionTier,
}
impl OsrFrameState {
pub fn new(
function_id: u64,
loop_header_offset: u32,
register_values: Vec<i64>,
accumulator: i64,
local_count: u32,
source_tier: ExecutionTier,
) -> Self {
Self {
loop_header_offset,
function_id,
register_values,
accumulator,
local_count,
source_tier,
}
}
}
#[derive(Debug, Clone)]
pub struct OsrRequest {
pub frame_state: OsrFrameState,
pub target_tier: ExecutionTier,
}
#[derive(Debug)]
pub struct OsrState {
counters: HashMap<u32, u32>,
pending_request: Option<OsrRequest>,
pub current_tier: ExecutionTier,
}
impl OsrState {
pub fn new() -> Self {
Self {
counters: HashMap::new(),
pending_request: None,
current_tier: ExecutionTier::Interpreter,
}
}
pub fn record_back_edge(
&mut self,
loop_offset: u32,
make_frame_state: impl FnOnce() -> OsrFrameState,
) -> Option<OsrRequest> {
let counter = self.counters.entry(loop_offset).or_insert(0);
*counter += 1;
let threshold = self.current_tier.osr_threshold();
if *counter >= threshold
&& let Some(target) = self.current_tier.next()
{
let request = OsrRequest {
frame_state: make_frame_state(),
target_tier: target,
};
self.pending_request = Some(request.clone());
return Some(request);
}
None
}
pub fn take_request(&mut self) -> Option<OsrRequest> {
self.pending_request.take()
}
pub fn reset_counter(&mut self, loop_offset: u32) {
self.counters.remove(&loop_offset);
}
pub fn complete_transition(&mut self, new_tier: ExecutionTier) {
self.current_tier = new_tier;
self.counters.clear();
self.pending_request = None;
}
}
impl Default for OsrState {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tier_transitions() {
assert_eq!(
ExecutionTier::Interpreter.next(),
Some(ExecutionTier::Baseline)
);
assert_eq!(ExecutionTier::Baseline.next(), Some(ExecutionTier::Maglev));
assert_eq!(ExecutionTier::Maglev.next(), Some(ExecutionTier::Turbofan));
assert_eq!(ExecutionTier::Turbofan.next(), None);
}
#[test]
fn test_osr_threshold_values() {
assert_eq!(
ExecutionTier::Interpreter.osr_threshold(),
OSR_INTERP_TO_BASELINE
);
assert_eq!(
ExecutionTier::Baseline.osr_threshold(),
OSR_BASELINE_TO_MAGLEV
);
assert_eq!(ExecutionTier::Turbofan.osr_threshold(), u32::MAX);
}
#[test]
fn test_osr_state_no_trigger_below_threshold() {
let mut state = OsrState::new();
for _ in 0..OSR_INTERP_TO_BASELINE - 1 {
let req = state.record_back_edge(0, || {
OsrFrameState::new(1, 0, vec![], 0, 0, ExecutionTier::Interpreter)
});
assert!(req.is_none());
}
}
#[test]
fn test_osr_state_triggers_at_threshold() {
let mut state = OsrState::new();
let mut req = None;
for _ in 0..OSR_INTERP_TO_BASELINE {
req = state.record_back_edge(0, || {
OsrFrameState::new(1, 0, vec![42], 99, 1, ExecutionTier::Interpreter)
});
}
let req = req.expect("OSR must trigger at threshold");
assert_eq!(req.target_tier, ExecutionTier::Baseline);
assert_eq!(req.frame_state.accumulator, 99);
assert_eq!(req.frame_state.register_values, vec![42]);
}
#[test]
fn test_osr_state_complete_transition() {
let mut state = OsrState::new();
for _ in 0..OSR_INTERP_TO_BASELINE {
state.record_back_edge(0, || {
OsrFrameState::new(1, 0, vec![], 0, 0, ExecutionTier::Interpreter)
});
}
state.complete_transition(ExecutionTier::Baseline);
assert_eq!(state.current_tier, ExecutionTier::Baseline);
assert!(state.pending_request.is_none());
}
#[test]
fn test_osr_frame_state_fields() {
let fs = OsrFrameState::new(42, 10, vec![1, 2, 3], -1, 3, ExecutionTier::Baseline);
assert_eq!(fs.function_id, 42);
assert_eq!(fs.loop_header_offset, 10);
assert_eq!(fs.register_values.len(), 3);
assert_eq!(fs.accumulator, -1);
assert_eq!(fs.local_count, 3);
assert_eq!(fs.source_tier, ExecutionTier::Baseline);
}
#[test]
fn test_turbofan_tier_no_osr() {
let mut state = OsrState {
current_tier: ExecutionTier::Turbofan,
..OsrState::new()
};
for _ in 0..100 {
let req = state.record_back_edge(0, || {
OsrFrameState::new(1, 0, vec![], 0, 0, ExecutionTier::Turbofan)
});
assert!(req.is_none(), "Turbofan is top tier — no further OSR");
}
}
}