diff --git a/Source/WTF/wtf/RunLoop.h b/Source/WTF/wtf/RunLoop.h index 0c67601ff6d02..110163098d3b5 100644 --- a/Source/WTF/wtf/RunLoop.h +++ b/Source/WTF/wtf/RunLoop.h @@ -195,6 +195,11 @@ class WTF_CAPABILITY("is current") RunLoop final : public GuaranteedSerialFuncti #elif USE(BUN_EVENT_LOOP) // WTFTimer in Timer.zig struct Bun__WTFTimer; + // Called from stop() once the backend has removed a still-armed timer + // from its heap, i.e. fired() is not running and will not run. Used by + // DispatchTimer to drop the self-ref dispatchAfter() stores in + // m_function; other subclasses have nothing to release. + virtual void didStopWhileActive() { } #endif ASCIILiteral description() const { return m_description; } @@ -337,6 +342,13 @@ class WTF_CAPABILITY("is current") RunLoop final : public GuaranteedSerialFuncti } private: void fired() final { m_function(); } +#if USE(BUN_EVENT_LOOP) + // dispatchAfter() captures a Ref to this timer inside m_function; + // dropping it here breaks the cycle when a caller stops the timer + // before it fires. stop() only calls this once the Bun-side heap has + // removed the still-armed node, so m_function is not on any stack. + void didStopWhileActive() final { m_function = { }; } +#endif Function m_function; }; diff --git a/Source/WTF/wtf/bun/RunLoopBun.cpp b/Source/WTF/wtf/bun/RunLoopBun.cpp index 6127aff064c78..6315ccb312665 100644 --- a/Source/WTF/wtf/bun/RunLoopBun.cpp +++ b/Source/WTF/wtf/bun/RunLoopBun.cpp @@ -22,7 +22,9 @@ extern "C" __attribute__((weak)) void WTFTimer__update(RunLoop::TimerBase::Bun__ extern "C" __attribute__((weak)) void WTFTimer__deinit(RunLoop::TimerBase::Bun__WTFTimer*); extern "C" __attribute__((weak)) bool WTFTimer__isActive(const RunLoop::TimerBase::Bun__WTFTimer*); extern "C" __attribute__((weak)) double WTFTimer__secondsUntilTimer(const RunLoop::TimerBase::Bun__WTFTimer*); -extern "C" __attribute__((weak)) void WTFTimer__cancel(RunLoop::TimerBase::Bun__WTFTimer*); +// Returns whether the timer was still armed in Bun's wtf_timers heap (i.e. +// fired() has not been and will not be dispatched for it). +extern "C" __attribute__((weak)) bool WTFTimer__cancel(RunLoop::TimerBase::Bun__WTFTimer*); // Weak, so that Bun can override it extern "C" __attribute__((weak)) bool Bun__thisThreadHasVM(); @@ -89,7 +91,8 @@ void RunLoop::TimerBase::stop() return stopGeneric(); case Kind::Bun: if (auto* ref = std::get_if>(&m_impl)) { - WTFTimer__cancel(&ref->get()); + if (WTFTimer__cancel(&ref->get())) + didStopWhileActive(); } return; }