(
&self,
frame: FrameRef,
exc: Option<PyBaseExceptionRef>,
traced: bool,
f: F,
)
| 1576 | } |
| 1577 | |
| 1578 | fn with_frame_impl<R, F: FnOnce(FrameRef) -> PyResult<R>>( |
| 1579 | &self, |
| 1580 | frame: FrameRef, |
| 1581 | exc: Option<PyBaseExceptionRef>, |
| 1582 | traced: bool, |
| 1583 | f: F, |
| 1584 | ) -> PyResult<R> { |
| 1585 | self.with_recursion("", || { |
| 1586 | // SAFETY: `frame` (FrameRef) stays alive for the entire closure scope, |
| 1587 | // keeping the FramePtr valid. We pass a clone to `f` so that `f` |
| 1588 | // consuming its FrameRef doesn't invalidate our pointer. |
| 1589 | let fp = FramePtr(NonNull::from(&*frame)); |
| 1590 | self.frames.borrow_mut().push(fp); |
| 1591 | // Update the shared frame stack for sys._current_frames() and faulthandler |
| 1592 | #[cfg(feature = "threading")] |
| 1593 | crate::vm::thread::push_thread_frame(fp); |
| 1594 | // Link frame into the signal-safe frame chain (previous pointer) |
| 1595 | let old_frame = crate::vm::thread::set_current_frame((&**frame) as *const Frame); |
| 1596 | frame.previous.store( |
| 1597 | old_frame as *mut Frame, |
| 1598 | core::sync::atomic::Ordering::Relaxed, |
| 1599 | ); |
| 1600 | // Push exception context for frame isolation. |
| 1601 | // For normal calls: None (clean slate). |
| 1602 | // For generators: the saved exception from last yield. |
| 1603 | self.push_exception(exc); |
| 1604 | let old_owner = frame.owner.swap( |
| 1605 | crate::frame::FrameOwner::Thread as i8, |
| 1606 | core::sync::atomic::Ordering::AcqRel, |
| 1607 | ); |
| 1608 | |
| 1609 | // Ensure cleanup on panic: restore owner, pop exception, frame chain, and frames Vec. |
| 1610 | scopeguard::defer! { |
| 1611 | frame.owner.store(old_owner, core::sync::atomic::Ordering::Release); |
| 1612 | self.pop_exception(); |
| 1613 | crate::vm::thread::set_current_frame(old_frame); |
| 1614 | self.frames.borrow_mut().pop(); |
| 1615 | #[cfg(feature = "threading")] |
| 1616 | crate::vm::thread::pop_thread_frame(); |
| 1617 | } |
| 1618 | |
| 1619 | if traced { |
| 1620 | self.dispatch_traced_frame(&frame, |frame| f(frame.to_owned())) |
| 1621 | } else { |
| 1622 | f(frame.to_owned()) |
| 1623 | } |
| 1624 | }) |
| 1625 | } |
| 1626 | |
| 1627 | /// Lightweight frame execution for generator/coroutine resume. |
| 1628 | /// Pushes to the thread frame stack and fires trace/profile events, |
no test coverage detected