Fire trace/profile 'call' and 'return' events around a frame body. Matches `call_trace_protected` / `trace_trampoline` protocol: - Fire `TraceEvent::Call`; if the trace function returns non-None, install it as the per-frame `f_trace`. - Execute the closure (the actual frame body). - Fire `TraceEvent::Return` on both normal return **and** exception unwind (`PY_UNWIND` → `PyTrace_RETURN` with `arg
(
&self,
frame: &Py<Frame>,
f: F,
)
| 1684 | /// unwind (`PY_UNWIND` → `PyTrace_RETURN` with `arg = None`). |
| 1685 | /// Propagate any trace-function error, replacing the original exception. |
| 1686 | fn dispatch_traced_frame<R, F: FnOnce(&Py<Frame>) -> PyResult<R>>( |
| 1687 | &self, |
| 1688 | frame: &Py<Frame>, |
| 1689 | f: F, |
| 1690 | ) -> PyResult<R> { |
| 1691 | use crate::protocol::TraceEvent; |
| 1692 | |
| 1693 | // Fire 'call' trace event. current_frame() now returns the callee. |
| 1694 | let trace_result = self.trace_event(TraceEvent::Call, None)?; |
| 1695 | if let Some(local_trace) = trace_result { |
| 1696 | *frame.trace.lock() = local_trace; |
| 1697 | } |
| 1698 | |
| 1699 | let result = f(frame); |
| 1700 | |
| 1701 | // Fire 'return' event if frame is being traced or profiled. |
| 1702 | // PY_UNWIND fires PyTrace_RETURN with arg=None — so we fire for |
| 1703 | // both Ok and Err, matching `call_trace_protected` behavior. |
| 1704 | if self.use_tracing.get() |
| 1705 | && (!self.is_none(&frame.trace.lock()) || !self.is_none(&self.profile_func.borrow())) |
| 1706 | { |
| 1707 | let ret_result = self.trace_event(TraceEvent::Return, None); |
| 1708 | // call_trace_protected: if trace function raises, its error |
| 1709 | // replaces the original exception. |
| 1710 | ret_result?; |
| 1711 | } |
| 1712 | |
| 1713 | result |
| 1714 | } |
| 1715 | |
| 1716 | /// Returns a basic CompileOpts instance with options accurate to the vm. Used |
| 1717 | /// as the CompileOpts for `vm.compile()`. |