diff --git a/Lib/test/test_doctest/test_doctest.py b/Lib/test/test_doctest/test_doctest.py index ec008ed38b6..4a42abf44e5 100644 --- a/Lib/test/test_doctest/test_doctest.py +++ b/Lib/test/test_doctest/test_doctest.py @@ -2063,7 +2063,7 @@ def test_pdb_set_trace(): ... 'continue', # stop debugging ... '']) - >>> try: runner.run(test) # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE + >>> try: runner.run(test) ... finally: sys.stdin = real_stdin > (1)() -> import pdb; pdb.set_trace() @@ -2091,7 +2091,7 @@ def test_pdb_set_trace(): ... 'continue', # stop debugging ... '']) - >>> try: # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE + >>> try: ... runner.run(test) ... finally: ... sys.stdin = real_stdin @@ -2209,7 +2209,7 @@ def test_pdb_set_trace_nested(): ... 'continue', # stop debugging ... '']) - >>> try: # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE + >>> try: ... runner.run(test) ... finally: ... sys.stdin = real_stdin diff --git a/crates/vm/src/frame.rs b/crates/vm/src/frame.rs index 7be72b4ea0a..e35efff6f19 100644 --- a/crates/vm/src/frame.rs +++ b/crates/vm/src/frame.rs @@ -750,36 +750,43 @@ impl ExecutingFrame<'_> { let bytecode::CodeUnit { op, arg } = instructions[idx]; let arg = arg_state.extend(arg); let mut do_extend_arg = false; + let caches = op.cache_entries(); - if !matches!( - op, - Instruction::Resume { .. } - | Instruction::ExtendedArg - | Instruction::InstrumentedLine - ) && let Some((loc, _)) = self.code.locations.get(idx) - { - self.state.prev_line = loc.line.get() as u32; - } - - // Fire 'opcode' trace event for sys.settrace when f_trace_opcodes - // is set. Skip RESUME and ExtendedArg (matching CPython's exclusion - // of these in _Py_call_instrumentation_instruction). - if vm.use_tracing.get() - && !vm.is_none(&self.object.trace.lock()) - && *self.object.trace_opcodes.lock() - && !matches!( + // Update prev_line only when tracing or monitoring is active. + // When neither is enabled, prev_line is stale but unused. + if vm.use_tracing.get() { + if !matches!( op, Instruction::Resume { .. } - | Instruction::InstrumentedResume | Instruction::ExtendedArg - ) - { - vm.trace_event(crate::protocol::TraceEvent::Opcode, None)?; + | Instruction::InstrumentedLine + ) && let Some((loc, _)) = self.code.locations.get(idx) + { + self.state.prev_line = loc.line.get() as u32; + } + + // Fire 'opcode' trace event for sys.settrace when f_trace_opcodes + // is set. Skip RESUME and ExtendedArg (matching CPython's exclusion + // of these in _Py_call_instrumentation_instruction). + if !vm.is_none(&self.object.trace.lock()) + && *self.object.trace_opcodes.lock() + && !matches!( + op, + Instruction::Resume { .. } + | Instruction::InstrumentedResume + | Instruction::ExtendedArg + ) + { + vm.trace_event(crate::protocol::TraceEvent::Opcode, None)?; + } } let lasti_before = self.lasti(); let result = self.execute_instruction(op, arg, &mut do_extend_arg, vm); - self.skip_caches_if_fallthrough(op, lasti_before); + // Skip inline cache entries if instruction fell through (no jump). + if caches > 0 && self.lasti() == lasti_before { + self.update_lasti(|i| *i += caches as u32); + } match result { Ok(None) => {} Ok(Some(value)) => { @@ -3409,7 +3416,10 @@ impl ExecutingFrame<'_> { let mut do_extend_arg = false; self.execute_instruction(original_op, arg, &mut do_extend_arg, vm) }; - self.skip_caches_if_fallthrough(original_op, lasti_before_dispatch); + let orig_caches = original_op.to_base().unwrap_or(original_op).cache_entries(); + if orig_caches > 0 && self.lasti() == lasti_before_dispatch { + self.update_lasti(|i| *i += orig_caches as u32); + } result } Instruction::InstrumentedInstruction => { @@ -3441,7 +3451,10 @@ impl ExecutingFrame<'_> { let mut do_extend_arg = false; self.execute_instruction(original_op, arg, &mut do_extend_arg, vm) }; - self.skip_caches_if_fallthrough(original_op, lasti_before_dispatch); + let orig_caches = original_op.to_base().unwrap_or(original_op).cache_entries(); + if orig_caches > 0 && self.lasti() == lasti_before_dispatch { + self.update_lasti(|i| *i += orig_caches as u32); + } result } _ => { @@ -4106,19 +4119,6 @@ impl ExecutingFrame<'_> { self.update_lasti(|i| *i = target); } - /// Skip past CACHE code units after an instruction, but only if the - /// instruction did not modify lasti (i.e., it did not jump). - #[inline] - fn skip_caches_if_fallthrough(&mut self, op: Instruction, lasti_before: u32) { - if self.lasti() == lasti_before { - let base = op.to_base().unwrap_or(op); - let caches = base.cache_entries(); - if caches > 0 { - self.update_lasti(|i| *i += caches as u32); - } - } - } - #[inline] fn pop_jump_if_relative( &mut self,