Skip to content

Commit e5a5232

Browse files
committed
fix(jit): invalidate native traces on local mutation
1 parent e5458f9 commit e5a5232

2 files changed

Lines changed: 50 additions & 1 deletion

File tree

src/vm/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2767,7 +2767,7 @@ impl Vm {
27672767
pub fn set_local(&mut self, index: u8, value: Value) -> VmResult<()> {
27682768
self.store_local_with_drop_contract(index, value)?;
27692769
let config = *self.jit.config();
2770-
self.jit.set_config(config);
2770+
self.set_jit_config(config);
27712771
Ok(())
27722772
}
27732773

tests/jit/jit_tests.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6498,6 +6498,55 @@ fn trace_jit_guards_static_inline_callable_identity() {
64986498
assert!(vm.jit_native_exec_count() > 0, "{}", vm.dump_jit_info());
64996499
}
65006500

6501+
#[test]
6502+
fn trace_jit_invalidates_native_inline_after_callable_local_replacement() {
6503+
if !native_jit_supported() {
6504+
return;
6505+
}
6506+
let source = r#"
6507+
fn add_one(value: int) -> int { value + 1 }
6508+
fn add_ten(value: int) -> int { value + 10 }
6509+
let mut i = 0;
6510+
let mut total = 0;
6511+
while i < 100 {
6512+
total = add_one(total);
6513+
i = i + 1;
6514+
}
6515+
total;
6516+
"#;
6517+
let compiled = compile_source(source).expect("callable invalidation source should compile");
6518+
let bindings = compiled.program.root_callable_bindings.clone();
6519+
let replaced_slot = bindings.first().expect("add_one binding").local_slot;
6520+
let replacement_id = bindings.get(1).expect("add_ten binding").prototype_id;
6521+
let replacement_kind = compiled.program.callable_prototypes[replacement_id as usize].kind;
6522+
let mut vm = Vm::new(compiled.program.with_local_count(compiled.locals));
6523+
vm.set_jit_config(JitConfig {
6524+
enabled: true,
6525+
hot_loop_threshold: 1,
6526+
max_trace_len: 512,
6527+
});
6528+
6529+
assert_eq!(vm.run().expect("initial inline run"), VmStatus::Halted);
6530+
assert_eq!(vm.stack(), &[Value::Int(100)]);
6531+
assert!(vm.jit_native_trace_count() > 0, "{}", vm.dump_jit_info());
6532+
6533+
vm.reset_for_reuse();
6534+
vm.set_local(
6535+
u8::try_from(replaced_slot).expect("root callable slot should fit u8"),
6536+
Value::Callable(Arc::new(vm::CallableValue {
6537+
prototype_id: replacement_id,
6538+
kind: replacement_kind,
6539+
env: None,
6540+
})),
6541+
)
6542+
.expect("callable replacement should succeed");
6543+
assert_eq!(vm.jit_native_trace_count(), 0);
6544+
6545+
assert_eq!(vm.run().expect("replacement inline run"), VmStatus::Halted);
6546+
assert_eq!(vm.stack(), &[Value::Int(1_000)]);
6547+
assert!(vm.jit_native_exec_count() > 0, "{}", vm.dump_jit_info());
6548+
}
6549+
65016550
#[test]
65026551
fn trace_jit_preserves_inline_callable_argument_schema_checks() {
65036552
if !native_jit_supported() {

0 commit comments

Comments
 (0)