mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Bug 1438541 P1 Track DOMEventTargetHelper objects in the nsIGlobalObject base class and always call DisconnectFromOwner() on them. r=smaug
This commit is contained in:
parent
582b8ef5c5
commit
f696313a4a
@ -1102,29 +1102,6 @@ nsGlobalWindowInner::~nsGlobalWindowInner()
|
||||
nsLayoutStatics::Release();
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::AddEventTargetObject(DOMEventTargetHelper* aObject)
|
||||
{
|
||||
mEventTargetObjects.PutEntry(aObject);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::RemoveEventTargetObject(DOMEventTargetHelper* aObject)
|
||||
{
|
||||
mEventTargetObjects.RemoveEntry(aObject);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::DisconnectEventTargetObjects()
|
||||
{
|
||||
for (auto iter = mEventTargetObjects.ConstIter(); !iter.Done();
|
||||
iter.Next()) {
|
||||
RefPtr<DOMEventTargetHelper> target = iter.Get()->GetKey();
|
||||
target->DisconnectFromOwner();
|
||||
}
|
||||
mEventTargetObjects.Clear();
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsGlobalWindowInner::ShutDown()
|
||||
@ -6907,6 +6884,8 @@ void
|
||||
nsGlobalWindowInner::AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const
|
||||
{
|
||||
aWindowSizes.mDOMOtherSize += aWindowSizes.mState.mMallocSizeOf(this);
|
||||
aWindowSizes.mDOMOtherSize +=
|
||||
nsIGlobalObject::ShallowSizeOfExcludingThis(aWindowSizes.mState.mMallocSizeOf);
|
||||
|
||||
EventListenerManager* elm = GetExistingListenerManager();
|
||||
if (elm) {
|
||||
@ -6929,12 +6908,7 @@ nsGlobalWindowInner::AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const
|
||||
mNavigator->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf);
|
||||
}
|
||||
|
||||
aWindowSizes.mDOMEventTargetsSize +=
|
||||
mEventTargetObjects.ShallowSizeOfExcludingThis(
|
||||
aWindowSizes.mState.mMallocSizeOf);
|
||||
|
||||
for (auto iter = mEventTargetObjects.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
DOMEventTargetHelper* et = iter.Get()->GetKey();
|
||||
ForEachEventTargetObject([&] (DOMEventTargetHelper* et) {
|
||||
if (nsCOMPtr<nsISizeOfEventTarget> iSizeOf = do_QueryObject(et)) {
|
||||
aWindowSizes.mDOMEventTargetsSize +=
|
||||
iSizeOf->SizeOfEventTargetIncludingThis(
|
||||
@ -6944,7 +6918,7 @@ nsGlobalWindowInner::AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const
|
||||
aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
|
||||
}
|
||||
++aWindowSizes.mDOMEventTargetsCount;
|
||||
}
|
||||
});
|
||||
|
||||
if (mPerformance) {
|
||||
aWindowSizes.mDOMPerformanceUserEntries =
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
@ -92,7 +91,6 @@ class DialogValueHolder;
|
||||
|
||||
namespace mozilla {
|
||||
class AbstractThread;
|
||||
class DOMEventTargetHelper;
|
||||
class ThrottledEventQueue;
|
||||
namespace dom {
|
||||
class BarProp;
|
||||
@ -517,10 +515,6 @@ public:
|
||||
|
||||
void AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const;
|
||||
|
||||
// Inner windows only.
|
||||
void AddEventTargetObject(mozilla::DOMEventTargetHelper* aObject);
|
||||
void RemoveEventTargetObject(mozilla::DOMEventTargetHelper* aObject);
|
||||
|
||||
void NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
|
||||
bool aCallOnidle);
|
||||
nsresult HandleIdleActiveEvent();
|
||||
@ -1259,8 +1253,6 @@ private:
|
||||
// Fire the JS engine's onNewGlobalObject hook. Only used on inner windows.
|
||||
void FireOnNewGlobalObject();
|
||||
|
||||
void DisconnectEventTargetObjects();
|
||||
|
||||
// nsPIDOMWindow{Inner,Outer} should be able to see these helper methods.
|
||||
friend class nsPIDOMWindowInner;
|
||||
friend class nsPIDOMWindowOuter;
|
||||
@ -1428,8 +1420,6 @@ protected:
|
||||
// currently enabled on this window.
|
||||
bool mAreDialogsEnabled;
|
||||
|
||||
nsTHashtable<nsPtrHashKey<mozilla::DOMEventTargetHelper> > mEventTargetObjects;
|
||||
|
||||
nsTArray<uint32_t> mEnabledSensors;
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
|
@ -11,7 +11,9 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsHostObjectProtocolHandler.h"
|
||||
|
||||
using mozilla::MallocSizeOf;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::DOMEventTargetHelper;
|
||||
using mozilla::dom::ClientInfo;
|
||||
using mozilla::dom::ServiceWorker;
|
||||
using mozilla::dom::ServiceWorkerDescriptor;
|
||||
@ -19,6 +21,8 @@ using mozilla::dom::ServiceWorkerDescriptor;
|
||||
nsIGlobalObject::~nsIGlobalObject()
|
||||
{
|
||||
UnlinkHostObjectURIs();
|
||||
DisconnectEventTargetObjects();
|
||||
MOZ_DIAGNOSTIC_ASSERT(mEventTargetObjects.IsEmpty());
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
@ -120,6 +124,51 @@ nsIGlobalObject::TraverseHostObjectURIs(nsCycleCollectionTraversalCallback &aCb)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsIGlobalObject::AddEventTargetObject(DOMEventTargetHelper* aObject)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aObject);
|
||||
MOZ_ASSERT(!mEventTargetObjects.Contains(aObject));
|
||||
mEventTargetObjects.PutEntry(aObject);
|
||||
}
|
||||
|
||||
void
|
||||
nsIGlobalObject::RemoveEventTargetObject(DOMEventTargetHelper* aObject)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aObject);
|
||||
MOZ_ASSERT(mEventTargetObjects.Contains(aObject));
|
||||
mEventTargetObjects.RemoveEntry(aObject);
|
||||
}
|
||||
|
||||
void
|
||||
nsIGlobalObject::ForEachEventTargetObject(const std::function<void(DOMEventTargetHelper*)>& aFunc) const
|
||||
{
|
||||
// Protect against the function call triggering a mutation of the hash table
|
||||
// while we are iterating by copying the DETH references to a temporary
|
||||
// list.
|
||||
AutoTArray<DOMEventTargetHelper*, 64> targetList;
|
||||
for (auto iter = mEventTargetObjects.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
targetList.AppendElement(iter.Get()->GetKey());
|
||||
}
|
||||
|
||||
// Iterate the target list and call the function on each one.
|
||||
for (auto target : targetList) {
|
||||
aFunc(target);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsIGlobalObject::DisconnectEventTargetObjects()
|
||||
{
|
||||
ForEachEventTargetObject([&] (DOMEventTargetHelper* aTarget) {
|
||||
aTarget->DisconnectFromOwner();
|
||||
|
||||
// Calling DisconnectFromOwner() should result in
|
||||
// RemoveEventTargetObject() being called.
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mEventTargetObjects.Contains(aTarget));
|
||||
});
|
||||
}
|
||||
|
||||
Maybe<ClientInfo>
|
||||
nsIGlobalObject::GetClientInfo() const
|
||||
{
|
||||
@ -154,3 +203,11 @@ nsIGlobalObject::RemoveServiceWorker(ServiceWorker* aServiceWorker)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "this global should not have any service workers");
|
||||
}
|
||||
|
||||
size_t
|
||||
nsIGlobalObject::ShallowSizeOfExcludingThis(MallocSizeOf aSizeOf) const
|
||||
{
|
||||
size_t rtn = mHostObjectURIs.ShallowSizeOfExcludingThis(aSizeOf);
|
||||
rtn += mEventTargetObjects.ShallowSizeOfExcludingThis(aSizeOf);
|
||||
return rtn;
|
||||
}
|
||||
|
@ -11,9 +11,11 @@
|
||||
#include "mozilla/dom/ClientInfo.h"
|
||||
#include "mozilla/dom/DispatcherTrait.h"
|
||||
#include "mozilla/dom/ServiceWorkerDescriptor.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
// Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs
|
||||
@ -25,6 +27,7 @@ class nsCycleCollectionTraversalCallback;
|
||||
class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
class DOMEventTargetHelper;
|
||||
namespace dom {
|
||||
class ServiceWorker;
|
||||
} // namespace dom
|
||||
@ -34,6 +37,13 @@ class nsIGlobalObject : public nsISupports,
|
||||
public mozilla::dom::DispatcherTrait
|
||||
{
|
||||
nsTArray<nsCString> mHostObjectURIs;
|
||||
|
||||
// Raw pointers to bound DETH objects. These are added by
|
||||
// AddEventTargetObject(). The DETH object must call
|
||||
// RemoveEventTargetObject() before its destroyed to clear
|
||||
// its raw pointer here.
|
||||
nsTHashtable<nsPtrHashKey<mozilla::DOMEventTargetHelper>> mEventTargetObjects;
|
||||
|
||||
bool mIsDying;
|
||||
|
||||
protected:
|
||||
@ -84,6 +94,18 @@ public:
|
||||
void UnlinkHostObjectURIs();
|
||||
void TraverseHostObjectURIs(nsCycleCollectionTraversalCallback &aCb);
|
||||
|
||||
// DETH objects must register themselves on the global when they
|
||||
// bind to it in order to get the DisconnectFromOwner() method
|
||||
// called correctly. RemoveEventTargetObject() must be called
|
||||
// before the DETH object is destroyed.
|
||||
void AddEventTargetObject(mozilla::DOMEventTargetHelper* aObject);
|
||||
void RemoveEventTargetObject(mozilla::DOMEventTargetHelper* aObject);
|
||||
|
||||
// Iterate the registered DETH objects and call the given function
|
||||
// for each one.
|
||||
void
|
||||
ForEachEventTargetObject(const std::function<void(mozilla::DOMEventTargetHelper*)>& aFunc) const;
|
||||
|
||||
virtual bool IsInSyncOperation() { return false; }
|
||||
|
||||
virtual mozilla::Maybe<mozilla::dom::ClientInfo>
|
||||
@ -115,6 +137,12 @@ protected:
|
||||
{
|
||||
mIsDying = true;
|
||||
}
|
||||
|
||||
void
|
||||
DisconnectEventTargetObjects();
|
||||
|
||||
size_t
|
||||
ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aSizeOf) const;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIGlobalObject,
|
||||
|
@ -89,8 +89,8 @@ NS_IMPL_DOMTARGET_DEFAULTS(DOMEventTargetHelper)
|
||||
|
||||
DOMEventTargetHelper::~DOMEventTargetHelper()
|
||||
{
|
||||
if (nsPIDOMWindowInner* owner = GetOwner()) {
|
||||
nsGlobalWindowInner::Cast(owner)->RemoveEventTargetObject(this);
|
||||
if (mParentObject) {
|
||||
mParentObject->RemoveEventTargetObject(this);
|
||||
}
|
||||
if (mListenerManager) {
|
||||
mListenerManager->Disconnect();
|
||||
@ -108,23 +108,21 @@ DOMEventTargetHelper::BindToOwner(nsPIDOMWindowInner* aOwner)
|
||||
void
|
||||
DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> parentObject = do_QueryReferent(mParentObject);
|
||||
if (parentObject) {
|
||||
if (mParentObject) {
|
||||
mParentObject->RemoveEventTargetObject(this);
|
||||
if (mOwnerWindow) {
|
||||
nsGlobalWindowInner::Cast(mOwnerWindow)->RemoveEventTargetObject(this);
|
||||
mOwnerWindow = nullptr;
|
||||
}
|
||||
mParentObject = nullptr;
|
||||
mHasOrHasHadOwnerWindow = false;
|
||||
}
|
||||
if (aOwner) {
|
||||
mParentObject = do_GetWeakReference(aOwner);
|
||||
MOZ_ASSERT(mParentObject, "All nsIGlobalObjects must support nsISupportsWeakReference");
|
||||
mParentObject = aOwner;
|
||||
aOwner->AddEventTargetObject(this);
|
||||
// Let's cache the result of this QI for fast access and off main thread usage
|
||||
mOwnerWindow = nsCOMPtr<nsPIDOMWindowInner>(do_QueryInterface(aOwner)).get();
|
||||
if (mOwnerWindow) {
|
||||
mHasOrHasHadOwnerWindow = true;
|
||||
nsGlobalWindowInner::Cast(mOwnerWindow)->AddEventTargetObject(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,22 +130,23 @@ DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner)
|
||||
void
|
||||
DOMEventTargetHelper::BindToOwner(DOMEventTargetHelper* aOther)
|
||||
{
|
||||
if (mParentObject) {
|
||||
mParentObject->RemoveEventTargetObject(this);
|
||||
}
|
||||
if (mOwnerWindow) {
|
||||
nsGlobalWindowInner::Cast(mOwnerWindow)->RemoveEventTargetObject(this);
|
||||
mOwnerWindow = nullptr;
|
||||
mParentObject = nullptr;
|
||||
mHasOrHasHadOwnerWindow = false;
|
||||
}
|
||||
if (aOther) {
|
||||
mHasOrHasHadOwnerWindow = aOther->HasOrHasHadOwner();
|
||||
if (aOther->GetParentObject()) {
|
||||
mParentObject = do_GetWeakReference(aOther->GetParentObject());
|
||||
MOZ_ASSERT(mParentObject, "All nsIGlobalObjects must support nsISupportsWeakReference");
|
||||
mParentObject = aOther->GetParentObject();
|
||||
if (mParentObject) {
|
||||
mParentObject->AddEventTargetObject(this);
|
||||
// Let's cache the result of this QI for fast access and off main thread usage
|
||||
mOwnerWindow = nsCOMPtr<nsPIDOMWindowInner>(do_QueryInterface(aOther->GetParentObject())).get();
|
||||
mOwnerWindow = nsCOMPtr<nsPIDOMWindowInner>(do_QueryInterface(mParentObject)).get();
|
||||
if (mOwnerWindow) {
|
||||
mHasOrHasHadOwnerWindow = true;
|
||||
nsGlobalWindowInner::Cast(mOwnerWindow)->AddEventTargetObject(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -156,6 +155,9 @@ DOMEventTargetHelper::BindToOwner(DOMEventTargetHelper* aOther)
|
||||
void
|
||||
DOMEventTargetHelper::DisconnectFromOwner()
|
||||
{
|
||||
if (mParentObject) {
|
||||
mParentObject->RemoveEventTargetObject(this);
|
||||
}
|
||||
mOwnerWindow = nullptr;
|
||||
mParentObject = nullptr;
|
||||
// Event listeners can't be handled anymore, so we can release them here.
|
||||
|
@ -146,8 +146,7 @@ public:
|
||||
using EventTarget::GetParentObject;
|
||||
virtual nsIGlobalObject* GetOwnerGlobal() const override
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> parentObject = do_QueryReferent(mParentObject);
|
||||
return parentObject;
|
||||
return mParentObject;
|
||||
}
|
||||
bool HasOrHasHadOwner() { return mHasOrHasHadOwnerWindow; }
|
||||
|
||||
@ -195,8 +194,9 @@ protected:
|
||||
void IgnoreKeepAliveIfHasListenersFor(nsAtom* aType);
|
||||
|
||||
private:
|
||||
// Inner window or sandbox.
|
||||
nsWeakPtr mParentObject;
|
||||
// The parent global object. The global will clear this when
|
||||
// it is destroyed by calling DisconnectFromOwner().
|
||||
nsIGlobalObject* MOZ_NON_OWNING_REF mParentObject;
|
||||
// mParentObject pre QI-ed and cached (inner window)
|
||||
// (it is needed for off main thread access)
|
||||
// It is obtained in BindToOwner and reset in DisconnectFromOwner.
|
||||
|
Loading…
Reference in New Issue
Block a user