Skip to content

Commit 821e648

Browse files
committed
Fix monitoring and specialization interaction
- cache_entries() returns correct count for instrumented opcodes - deoptimize() maps instrumented opcodes back to base - quicken() skips adaptive counter for instrumented opcodes - instrument_code Phase 3 deoptimizes specialized opcodes and clears CACHE entries to prevent stale pointer dereferences
1 parent 3bc025f commit 821e648

File tree

4 files changed

+41
-14
lines changed

4 files changed

+41
-14
lines changed

.cspell.dict/cpython.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ copyslot
4444
cpucount
4545
defaultdict
4646
denom
47+
deopt
4748
dictbytype
4849
DICTFLAG
4950
dictoffset

crates/compiler-core/src/bytecode.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -560,10 +560,14 @@ impl CodeUnits {
560560
let op = units[i].op;
561561
let caches = op.cache_entries();
562562
if caches > 0 {
563-
let cache_base = i + 1;
564-
if cache_base < len {
565-
unsafe {
566-
self.write_adaptive_counter(cache_base, ADAPTIVE_WARMUP_VALUE);
563+
// Don't write adaptive counter for instrumented opcodes;
564+
// specialization is skipped while monitoring is active.
565+
if !op.is_instrumented() {
566+
let cache_base = i + 1;
567+
if cache_base < len {
568+
unsafe {
569+
self.write_adaptive_counter(cache_base, ADAPTIVE_WARMUP_VALUE);
570+
}
567571
}
568572
}
569573
i += 1 + caches;

crates/compiler-core/src/bytecode/instruction.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,11 @@ impl Instruction {
620620
}
621621
// RESUME specializations
622622
Self::ResumeCheck => Self::Resume { arg: Arg::marker() },
623-
// Everything else maps to itself
624-
_ => self,
623+
// Instrumented opcodes map back to their base
624+
_ => match self.to_base() {
625+
Some(base) => base,
626+
None => self,
627+
},
625628
}
626629
}
627630

@@ -739,8 +742,11 @@ impl Instruction {
739742
| Self::UnpackSequenceTuple
740743
| Self::UnpackSequenceTwoTuple => 1,
741744

742-
// Everything else: 0 cache entries
743-
_ => 0,
745+
// Instrumented opcodes have the same cache entries as their base
746+
_ => match self.to_base() {
747+
Some(base) => base.cache_entries(),
748+
None => 0,
749+
},
744750
}
745751
}
746752
}

crates/vm/src/stdlib/sys/monitoring.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -270,13 +270,29 @@ pub fn instrument_code(code: &PyCode, events: u32) {
270270
}
271271
}
272272

273-
// Phase 3: Remove regular INSTRUMENTED_* → restore base opcodes
274-
for i in 0..len {
275-
let op = code.code.instructions[i].op;
276-
if let Some(base) = op.to_base() {
277-
unsafe {
278-
code.code.instructions.replace_op(i, base);
273+
// Phase 3: Remove regular INSTRUMENTED_* and specialized opcodes → restore base opcodes.
274+
// Also clear all CACHE entries so specialization starts fresh.
275+
{
276+
let mut i = 0;
277+
while i < len {
278+
let op = code.code.instructions[i].op;
279+
let de_opt = op.deoptimize();
280+
if u8::from(de_opt) != u8::from(op) {
281+
unsafe {
282+
code.code.instructions.replace_op(i, de_opt);
283+
}
284+
}
285+
let caches = de_opt.cache_entries();
286+
// Zero all CACHE entries (the op+arg bytes may have been overwritten
287+
// by specialization with arbitrary data like pointers).
288+
for c in 1..=caches {
289+
if i + c < len {
290+
unsafe {
291+
code.code.instructions.write_cache_u16(i + c, 0);
292+
}
293+
}
279294
}
295+
i += 1 + caches;
280296
}
281297
}
282298

0 commit comments

Comments
 (0)