Bug 798165 - Make nsTimeout more of a real cycle collected class. r=smaug

This commit is contained in:
Andrew McCreight 2013-04-30 10:41:23 -07:00
parent 3a107ba64a
commit f8f443ed5c
3 changed files with 31 additions and 68 deletions

View File

@ -495,6 +495,11 @@ nsTimeout::~nsTimeout()
}
#endif
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
MOZ_COUNT_DTOR(nsTimeout);
}
@ -507,6 +512,14 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
// Return true if this timeout has a refcount of 1. This is used to check
// that dummy_timeout doesn't leak from nsGlobalWindow::RunTimeout.
bool
nsTimeout::HasRefCntOne()
{
return mRefCnt.get() == 1;
}
nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
: mFrameElement(nullptr), mDocShell(nullptr), mModalStateDepth(0),
mRunningTimeout(nullptr), mMutationBits(0), mIsDocumentLoaded(false),
@ -10302,9 +10315,8 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
nsTimeout *nextTimeout, *timeout;
nsTimeout *nextTimeout;
nsTimeout *last_expired_timeout, *last_insertion_point;
nsTimeout dummy_timeout;
uint32_t firingDepth = mTimeoutFiringDepth + 1;
// Make sure that the window and the script context don't go away as
@ -10333,7 +10345,7 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
// timeout events fire "early", so we need to test the timer as well
// as the deadline.
last_expired_timeout = nullptr;
for (timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
for (nsTimeout *timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
(timeout->mFiringDepth == 0)) {
// Mark any timeouts that are on the list to be fired with the
@ -10365,24 +10377,21 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
// timeouts that will be processed in a future call to
// win_run_timeout(). This dummy timeout serves as the head of the
// list for any timeouts inserted as a result of running a timeout.
dummy_timeout.mFiringDepth = firingDepth;
dummy_timeout.mWhen = now;
last_expired_timeout->setNext(&dummy_timeout);
// Don't let ClearWindowTimeouts throw away our stack-allocated
// dummy timeout.
dummy_timeout.AddRef();
dummy_timeout.AddRef();
nsRefPtr<nsTimeout> dummy_timeout = new nsTimeout();
dummy_timeout->mFiringDepth = firingDepth;
dummy_timeout->mWhen = now;
last_expired_timeout->setNext(dummy_timeout);
dummy_timeout->AddRef();
last_insertion_point = mTimeoutInsertionPoint;
// If we ever start setting mTimeoutInsertionPoint to a non-dummy timeout,
// the logic in ResetTimersForNonBackgroundWindow will need to change.
mTimeoutInsertionPoint = &dummy_timeout;
mTimeoutInsertionPoint = dummy_timeout;
Telemetry::AutoCounter<Telemetry::DOM_TIMERS_FIRED_PER_NATIVE_TIMEOUT> timeoutsRan;
for (timeout = mTimeouts.getFirst();
timeout != &dummy_timeout && !IsFrozen();
for (nsTimeout *timeout = mTimeouts.getFirst();
timeout != dummy_timeout && !IsFrozen();
timeout = nextTimeout) {
nextTimeout = timeout->getNext();
@ -10436,6 +10445,7 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
// ClearAllTimeouts() was called from a *nested* call, possibly
// through a timeout that fired while a modal (to this window)
// dialog was open or through other non-obvious paths.
MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
mTimeoutInsertionPoint = last_insertion_point;
@ -10463,36 +10473,13 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
}
// Take the dummy timeout off the head of the list
dummy_timeout.remove();
dummy_timeout->remove();
dummy_timeout->Release();
MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
mTimeoutInsertionPoint = last_insertion_point;
}
nsrefcnt
nsTimeout::Release()
{
if (--mRefCnt > 0)
return mRefCnt;
// language specific cleanup done as mScriptHandler destructs...
// Kill the timer if it is still alive.
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
delete this;
return 0;
}
nsrefcnt
nsTimeout::AddRef()
{
return ++mRefCnt;
}
nsresult
nsGlobalWindow::ClearTimeoutOrInterval(int32_t aTimerID)
{

View File

@ -146,10 +146,8 @@ struct nsTimeout : mozilla::LinkedListElement<nsTimeout>
nsTimeout();
~nsTimeout();
NS_DECL_CYCLE_COLLECTION_LEGACY_NATIVE_CLASS(nsTimeout)
nsrefcnt Release();
nsrefcnt AddRef();
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsTimeout)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsTimeout)
nsresult InitTimer(nsTimerCallbackFunc aFunc, uint32_t aDelay)
{
@ -157,6 +155,8 @@ struct nsTimeout : mozilla::LinkedListElement<nsTimeout>
nsITimer::TYPE_ONE_SHOT);
}
bool HasRefCntOne();
// Window for which this timeout fires
nsRefPtr<nsGlobalWindow> mWindow;
@ -201,10 +201,6 @@ struct nsTimeout : mozilla::LinkedListElement<nsTimeout>
// The language-specific information about the callback.
nsCOMPtr<nsIScriptTimeoutHandler> mScriptHandler;
private:
// reference count for shared usage
nsAutoRefCnt mRefCnt;
};
struct IdleObserverHolder

View File

@ -749,9 +749,6 @@ struct Skippable
tmp->mRefCnt.ReleasePurpleBufferEntry(); \
}
#define NS_DECL_CYCLE_COLLECTION_STUB_UNMARK_IF_PURPLE(_class) \
static NS_METHOD_(void) UnmarkIfPurpleImpl(void *p) {}
#define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(_class) \
class NS_CYCLE_COLLECTION_INNERCLASS \
: public nsCycleCollectionParticipant \
@ -788,23 +785,6 @@ struct Skippable
} \
};
#define NS_DECL_CYCLE_COLLECTION_LEGACY_NATIVE_CLASS(_class) \
class NS_CYCLE_COLLECTION_INNERCLASS \
: public nsCycleCollectionParticipant \
{ \
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class) \
NS_DECL_CYCLE_COLLECTION_STUB_UNMARK_IF_PURPLE(_class) \
static nsCycleCollectionParticipant* GetParticipant() \
{ \
static const CCParticipantVTable<NS_CYCLE_COLLECTION_CLASSNAME(_class)> \
::Type p = { \
NS_IMPL_CYCLE_COLLECTION_NATIVE_VTABLE( \
NS_CYCLE_COLLECTION_CLASSNAME(_class)) \
}; \
return NS_PARTICIPANT_AS(nsCycleCollectionParticipant, &p); \
} \
};
#define NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(_class, _root_function) \
NS_METHOD \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::RootImpl(void *p) \