Skip to content

Commit a746d6e

Browse files
committed
fix(jit): cover callable backoff invalidation
1 parent 84726e9 commit a746d6e

2 files changed

Lines changed: 67 additions & 7 deletions

File tree

src/vm/jit/trace.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,67 @@ mod tests {
911911
}
912912
}
913913

914+
#[test]
915+
fn callable_frame_backoff_clears_on_jit_invalidation() {
916+
if !native_jit_supported() {
917+
return;
918+
}
919+
let mut bc = BytecodeBuilder::new();
920+
let root_ip = bc.position();
921+
bc.ldloc(0);
922+
bc.ldc(0);
923+
bc.add();
924+
bc.stloc(0);
925+
bc.br(root_ip);
926+
let mut program = Program::new(vec![Value::Int(1)], bc.finish()).with_local_count(1);
927+
program.script_functions.push(ScriptFunction {
928+
entry_ip: root_ip,
929+
end_ip: program.code.len() as u32,
930+
});
931+
program.callable_prototypes.push(CallablePrototype {
932+
kind: CallableKind::FunctionItem,
933+
target: CallableTarget::ScriptFunction(0),
934+
arity: 0,
935+
frame_local_count: 1,
936+
parameter_slots: Vec::new(),
937+
capture_source_slots: Vec::new(),
938+
capture_slots: Vec::new(),
939+
capture_modes: Vec::new(),
940+
self_slot: None,
941+
schema: None,
942+
});
943+
let config = JitConfig {
944+
enabled: true,
945+
hot_loop_threshold: 1,
946+
max_trace_len: 64,
947+
};
948+
let mut engine = TraceJitEngine::new(config);
949+
950+
let trace_id = engine
951+
.observe_hot_entry(0, root_ip as usize, 0, &program)
952+
.expect("script-frame trace should compile");
953+
for _ in 0..CALLABLE_SIDE_EXIT_BACKOFF_THRESHOLD {
954+
engine.record_native_side_exit(trace_id);
955+
}
956+
engine.block_callable_frame(trace_id);
957+
assert!(engine.callable_frame_is_blocked(0));
958+
959+
engine.set_config(config);
960+
assert!(!engine.callable_frame_is_blocked(0));
961+
962+
let trace_id = engine
963+
.observe_hot_entry(0, root_ip as usize, 0, &program)
964+
.expect("script-frame trace should recompile after config invalidation");
965+
for _ in 0..CALLABLE_SIDE_EXIT_BACKOFF_THRESHOLD {
966+
engine.record_native_side_exit(trace_id);
967+
}
968+
engine.block_callable_frame(trace_id);
969+
assert!(engine.callable_frame_is_blocked(0));
970+
971+
assert!(engine.set_non_yielding_host_imports(vec![true]));
972+
assert!(!engine.callable_frame_is_blocked(0));
973+
}
974+
914975
#[test]
915976
fn trace_entry_cache_separates_root_and_script_frames() {
916977
if !native_jit_supported() {

tests/jit/jit_tests.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4831,15 +4831,14 @@ fn trace_jit_executes_hot_loop_inside_script_callable_frame() {
48314831
);
48324832
assert_eq!(vm.stack(), &[Value::Int(4_950)]);
48334833
assert!(vm.jit_native_exec_count() > 0);
4834-
assert!(
4835-
vm.jit_snapshot().metrics.native_loop_back_count > 0,
4836-
"scalar callable loop should remain native across backedges: {}",
4837-
vm.dump_jit_info()
4838-
);
48394834
let snapshot = vm.jit_snapshot();
48404835
assert!(
4841-
snapshot.traces.iter().any(|trace| trace.frame_key == 0),
4842-
"expected a prototype-keyed trace: {}",
4836+
snapshot.traces.iter().any(|trace| {
4837+
trace.frame_key == 0
4838+
&& trace.terminal == JitTraceTerminal::LoopBack
4839+
&& trace.executions > 0
4840+
}),
4841+
"expected an executed prototype-keyed loopback trace: {}",
48434842
vm.dump_jit_info()
48444843
);
48454844
}

0 commit comments

Comments
 (0)