Skip to content

Commit c40e4b1

Browse files
committed
fix(jit): preserve region progress across side exits
1 parent 2910b9c commit c40e4b1

3 files changed

Lines changed: 68 additions & 1 deletion

File tree

src/vm/jit/runtime.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,15 @@ impl Vm {
321321

322322
loop {
323323
native::clear_bridge_error();
324+
let region_edges_before = self.jit_native_region_edge_count;
324325
let status = unsafe { entry(self as *mut Vm) };
325326
self.native_trace_exec_count = self.native_trace_exec_count.saturating_add(1);
326327
if is_region {
327328
self.jit_native_region_entry_count =
328329
self.jit_native_region_entry_count.saturating_add(1);
330+
if self.jit_native_region_edge_count > region_edges_before {
331+
self.jit.record_native_region_progress(current_trace_id);
332+
}
329333
}
330334
self.jit.mark_trace_executed(current_trace_id);
331335
let mut trace_exit_key = None;
@@ -823,11 +827,15 @@ impl Vm {
823827
) = self.native_trace_state(current_trace_id)?;
824828
native::clear_bridge_error();
825829
loop {
830+
let region_edges_before = self.jit_native_region_edge_count;
826831
let status = unsafe { entry(self as *mut Vm) };
827832
self.native_trace_exec_count = self.native_trace_exec_count.saturating_add(1);
828833
if is_region {
829834
self.jit_native_region_entry_count =
830835
self.jit_native_region_entry_count.saturating_add(1);
836+
if self.jit_native_region_edge_count > region_edges_before {
837+
self.jit.record_native_region_progress(current_trace_id);
838+
}
831839
}
832840
self.jit.mark_trace_executed(current_trace_id);
833841
let mut trace_exit_key = None;

src/vm/jit/trace.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,10 @@ impl TraceJitEngine {
712712
}
713713
}
714714

715+
pub(crate) fn record_native_region_progress(&mut self, trace_id: usize) {
716+
self.record_native_loop_back(trace_id);
717+
}
718+
715719
pub(crate) fn callable_frame_is_blocked(&self, frame_key: u64) -> bool {
716720
if frame_key == ROOT_FRAME_KEY {
717721
return false;
@@ -1609,7 +1613,7 @@ mod tests {
16091613
}
16101614

16111615
#[test]
1612-
fn callable_side_exit_backoff_resets_on_native_loopback() {
1616+
fn callable_side_exit_backoff_resets_on_native_progress() {
16131617
if !native_jit_supported() {
16141618
return;
16151619
}
@@ -1653,6 +1657,10 @@ mod tests {
16531657
for _ in 1..CALLABLE_SIDE_EXIT_BACKOFF_THRESHOLD {
16541658
assert!(!engine.record_native_side_exit(trace_id));
16551659
}
1660+
engine.record_native_region_progress(trace_id);
1661+
for _ in 1..CALLABLE_SIDE_EXIT_BACKOFF_THRESHOLD {
1662+
assert!(!engine.record_native_side_exit(trace_id));
1663+
}
16561664
assert!(engine.record_native_side_exit(trace_id));
16571665
engine.block_callable_frame(trace_id);
16581666
assert!(engine.callable_frame_is_blocked(0));

tests/jit/jit_tests.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2463,6 +2463,57 @@ fn trace_jit_region_preserves_owned_value_drop_contract() {
24632463
assert_eq!(Arc::strong_count(&output), 1);
24642464
}
24652465

2466+
#[test]
2467+
fn trace_jit_region_progress_prevents_callable_frame_backoff() {
2468+
if !native_jit_supported() {
2469+
return;
2470+
}
2471+
let source = r#"
2472+
fn run(limit, payload) {
2473+
let mut i = 0;
2474+
let mut total = 0;
2475+
while i < limit {
2476+
if i % 2 == 0 {
2477+
total = total + 3;
2478+
} else {
2479+
total = total + 5;
2480+
}
2481+
i = i + 1;
2482+
}
2483+
total + payload[0]
2484+
}
2485+
run(256, [1]);
2486+
"#;
2487+
let compiled = compile_source(source).expect("region progress fixture should compile");
2488+
let mut vm = Vm::new(compiled.program);
2489+
vm.set_jit_config(JitConfig {
2490+
enabled: true,
2491+
hot_loop_threshold: 1,
2492+
max_trace_len: 256,
2493+
});
2494+
2495+
assert_eq!(vm.run().unwrap(), VmStatus::Halted);
2496+
assert_eq!(vm.stack(), &[Value::Int(1_025)]);
2497+
assert_eq!(vm.jit_native_region_count(), 1, "{}", vm.dump_jit_info());
2498+
let first_execs = vm.jit_native_exec_count();
2499+
let first_edges = vm.jit_native_internal_region_edge_count();
2500+
2501+
vm.reset_for_reuse();
2502+
assert_eq!(vm.run().unwrap(), VmStatus::Halted);
2503+
assert_eq!(vm.stack(), &[Value::Int(1_025)]);
2504+
assert!(
2505+
vm.jit_native_exec_count() > first_execs,
2506+
"{}",
2507+
vm.dump_jit_info()
2508+
);
2509+
assert!(
2510+
vm.jit_native_internal_region_edge_count() > first_edges,
2511+
"{}",
2512+
vm.dump_jit_info()
2513+
);
2514+
assert_eq!(vm.jit_native_region_count(), 1, "{}", vm.dump_jit_info());
2515+
}
2516+
24662517
#[test]
24672518
fn trace_jit_region_respects_fuel_and_epoch_interrupts() {
24682519
if !native_jit_supported() {

0 commit comments

Comments
 (0)