Bug 1862244 - Add GlobalTeardownHelper. r=smaug, a=RyanVM

Differential Revision: https://phabricator.services.mozilla.com/D195131
This commit is contained in:
Kagami Sascha Rosylight 2023-11-30 18:46:02 +00:00
parent 1f892c76c8
commit b1c7724808
33 changed files with 305 additions and 213 deletions

View File

@ -2610,7 +2610,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(Document)
if (mql->HasListeners() &&
NS_SUCCEEDED(mql->CheckCurrentGlobalCorrectness())) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
cb.NoteXPCOMChild(mql);
cb.NoteXPCOMChild(static_cast<EventTarget*>(mql));
}
}

View File

@ -0,0 +1,73 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GlobalTeardownObserver.h"
#include "mozilla/Sprintf.h"
#include "mozilla/dom/Document.h"
namespace mozilla {
GlobalTeardownObserver::GlobalTeardownObserver() = default;
GlobalTeardownObserver::GlobalTeardownObserver(nsIGlobalObject* aGlobalObject,
bool aHasOrHasHadOwnerWindow)
: mHasOrHasHadOwnerWindow(aHasOrHasHadOwnerWindow) {
BindToOwner(aGlobalObject);
}
GlobalTeardownObserver::~GlobalTeardownObserver() {
if (mParentObject) {
mParentObject->RemoveGlobalTeardownObserver(this);
}
}
void GlobalTeardownObserver::BindToOwner(nsIGlobalObject* aOwner) {
MOZ_ASSERT(!mParentObject);
if (aOwner) {
mParentObject = aOwner;
aOwner->AddGlobalTeardownObserver(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;
}
}
}
void GlobalTeardownObserver::DisconnectFromOwner() {
if (mParentObject) {
mParentObject->RemoveGlobalTeardownObserver(this);
}
mOwnerWindow = nullptr;
mParentObject = nullptr;
}
nsresult GlobalTeardownObserver::CheckCurrentGlobalCorrectness() const {
NS_ENSURE_STATE(!mHasOrHasHadOwnerWindow || mOwnerWindow);
// Main-thread.
if (mOwnerWindow && !mOwnerWindow->IsCurrentInnerWindow()) {
return NS_ERROR_FAILURE;
}
if (NS_IsMainThread()) {
return NS_OK;
}
if (!mParentObject) {
return NS_ERROR_FAILURE;
}
if (mParentObject->IsDying()) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
}; // namespace mozilla

View File

@ -0,0 +1,87 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_BASE_GLOBALTEARDOWNOBSERVER_H_
#define DOM_BASE_GLOBALTEARDOWNOBSERVER_H_
#include "mozilla/Attributes.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/RefPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsID.h"
#include "nsIGlobalObject.h"
#include "nsIScriptGlobalObject.h"
#include "nsISupports.h"
#include "nsISupportsUtils.h"
#include "nsPIDOMWindow.h"
#define NS_GLOBALTEARDOWNOBSERVER_IID \
{ \
0xc31fddb9, 0xec49, 0x4f24, { \
0x90, 0x16, 0xb5, 0x2b, 0x26, 0x6c, 0xb6, 0x29 \
} \
}
namespace mozilla {
class GlobalTeardownObserver
: public nsISupports,
public LinkedListElement<GlobalTeardownObserver> {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_GLOBALTEARDOWNOBSERVER_IID)
GlobalTeardownObserver();
explicit GlobalTeardownObserver(nsIGlobalObject* aGlobalObject,
bool aHasOrHasHadOwnerWindow = false);
nsPIDOMWindowInner* GetOwner() const { return mOwnerWindow; }
nsIGlobalObject* GetOwnerGlobal() const { return mParentObject; }
bool HasOrHasHadOwner() { return mHasOrHasHadOwnerWindow; }
void GetParentObject(nsIScriptGlobalObject** aParentObject) {
if (mParentObject) {
CallQueryInterface(mParentObject, aParentObject);
} else {
*aParentObject = nullptr;
}
}
virtual void DisconnectFromOwner();
// A global permanently becomes invalid when DisconnectEventTargetObjects() is
// called. Normally this means:
// - For the main thread, when nsGlobalWindowInner::FreeInnerObjects is
// called.
// - For a worker thread, when clearing the main event queue. (Which we do
// slightly later than when the spec notionally calls for it to be done.)
//
// A global may also become temporarily invalid when:
// - For the main thread, if the window is no longer the WindowProxy's current
// inner window due to being placed in the bfcache.
nsresult CheckCurrentGlobalCorrectness() const;
protected:
virtual ~GlobalTeardownObserver();
void BindToOwner(nsIGlobalObject* aOwner);
private:
// The parent global object. The global will clear this when
// it is destroyed by calling DisconnectFromOwner().
nsIGlobalObject* MOZ_NON_OWNING_REF mParentObject = nullptr;
// 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.
nsPIDOMWindowInner* MOZ_NON_OWNING_REF mOwnerWindow = nullptr;
bool mHasOrHasHadOwnerWindow = false;
};
NS_DEFINE_STATIC_IID_ACCESSOR(GlobalTeardownObserver,
NS_GLOBALTEARDOWNOBSERVER_IID)
} // namespace mozilla
#endif

View File

@ -154,7 +154,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InProcessBrowserChildMessageManager)
NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager)
NS_INTERFACE_MAP_ENTRY(ContentFrameMessageManager)
NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentFrameMessageManager)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)

View File

@ -219,13 +219,15 @@ void VisualViewport::FireResizeEvent() {
VVP_LOG("%p, FireResizeEvent, fire mozvisualresize\n", this);
WidgetEvent mozEvent(true, eMozVisualResize);
mozEvent.mFlags.mOnlySystemGroupDispatch = true;
EventDispatcher::Dispatch(this, presContext, &mozEvent);
EventDispatcher::Dispatch(static_cast<EventTarget*>(this), presContext,
&mozEvent);
VVP_LOG("%p, FireResizeEvent, fire VisualViewport resize\n", this);
WidgetEvent event(true, eResize);
event.mFlags.mBubbles = false;
event.mFlags.mCancelable = false;
EventDispatcher::Dispatch(this, presContext, &event);
EventDispatcher::Dispatch(static_cast<EventTarget*>(this), presContext,
&event);
}
/* ================= Scroll event handling ================= */
@ -302,7 +304,8 @@ void VisualViewport::FireScrollEvent() {
VVP_LOG("%p: FireScrollEvent, fire mozvisualscroll\n", this);
WidgetEvent mozEvent(true, eMozVisualScroll);
mozEvent.mFlags.mOnlySystemGroupDispatch = true;
EventDispatcher::Dispatch(this, presContext, &mozEvent);
EventDispatcher::Dispatch(static_cast<EventTarget*>(this), presContext,
&mozEvent);
}
// Check whether the relative visual viewport offset actually changed -
@ -321,7 +324,8 @@ void VisualViewport::FireScrollEvent() {
WidgetGUIEvent event(true, eScroll, nullptr);
event.mFlags.mBubbles = false;
event.mFlags.mCancelable = false;
EventDispatcher::Dispatch(this, presContext, &event);
EventDispatcher::Dispatch(static_cast<EventTarget*>(this), presContext,
&event);
}
}
}

View File

@ -132,6 +132,7 @@ EXPORTS.mozilla += [
"CORSMode.h",
"FlushType.h",
"FullscreenChange.h",
"GlobalTeardownObserver.h",
"IdentifierMapEntry.h",
"PointerLockManager.h",
"RangeBoundary.h",
@ -359,6 +360,7 @@ UNIFIED_SOURCES += [
"FormData.cpp",
"FragmentOrElement.cpp",
"GeneratedImageContent.cpp",
"GlobalTeardownObserver.cpp",
"Highlight.cpp",
"HighlightRegistry.cpp",
"IdleDeadline.cpp",

View File

@ -3622,12 +3622,16 @@ class TreeOrderComparator {
} // namespace mozilla::dom
#define NS_INTERFACE_MAP_ENTRY_TEAROFF(_interface, _allocator) \
if (aIID.Equals(NS_GET_IID(_interface))) { \
foundInterface = static_cast<_interface*>(_allocator); \
if (!foundInterface) { \
*aInstancePtr = nullptr; \
return NS_ERROR_OUT_OF_MEMORY; \
} \
NS_INTERFACE_MAP_ENTRY_TEAROFF_AMBIGUOUS(_interface, _interface, _allocator)
#define NS_INTERFACE_MAP_ENTRY_TEAROFF_AMBIGUOUS(_interface, _implClass, \
_allocator) \
if (aIID.Equals(NS_GET_IID(_interface))) { \
foundInterface = static_cast<_implClass*>(_allocator); \
if (!foundInterface) { \
*aInstancePtr = nullptr; \
return NS_ERROR_OUT_OF_MEMORY; \
} \
} else
/*

View File

@ -1226,7 +1226,7 @@ void nsGlobalWindowInner::FreeInnerObjects() {
// that the Promises can resolve.
CallDocumentFlushedResolvers(/* aUntilExhaustion = */ true);
DisconnectEventTargetObjects();
DisconnectGlobalTeardownObservers();
#ifdef MOZ_WIDGET_ANDROID
DisableOrientationChangeListener();
@ -6043,15 +6043,16 @@ RefPtr<ServiceWorker> nsGlobalWindowInner::GetOrCreateServiceWorker(
const ServiceWorkerDescriptor& aDescriptor) {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<ServiceWorker> ref;
ForEachEventTargetObject([&](DOMEventTargetHelper* aTarget, bool* aDoneOut) {
RefPtr<ServiceWorker> sw = do_QueryObject(aTarget);
if (!sw || !sw->Descriptor().Matches(aDescriptor)) {
return;
}
ForEachGlobalTeardownObserver(
[&](GlobalTeardownObserver* aObserver, bool* aDoneOut) {
RefPtr<ServiceWorker> sw = do_QueryObject(aObserver);
if (!sw || !sw->Descriptor().Matches(aDescriptor)) {
return;
}
ref = std::move(sw);
*aDoneOut = true;
});
ref = std::move(sw);
*aDoneOut = true;
});
if (!ref) {
ref = ServiceWorker::Create(this, aDescriptor);
@ -6066,15 +6067,16 @@ nsGlobalWindowInner::GetServiceWorkerRegistration(
const {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<ServiceWorkerRegistration> ref;
ForEachEventTargetObject([&](DOMEventTargetHelper* aTarget, bool* aDoneOut) {
RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aTarget);
if (!swr || !swr->MatchesDescriptor(aDescriptor)) {
return;
}
ForEachGlobalTeardownObserver(
[&](GlobalTeardownObserver* aObserver, bool* aDoneOut) {
RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aObserver);
if (!swr || !swr->MatchesDescriptor(aDescriptor)) {
return;
}
ref = std::move(swr);
*aDoneOut = true;
});
ref = std::move(swr);
*aDoneOut = true;
});
return ref;
}
@ -6808,14 +6810,17 @@ void nsGlobalWindowInner::AddSizeOfIncludingThis(
mNavigator->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf);
}
ForEachEventTargetObject([&](DOMEventTargetHelper* et, bool* aDoneOut) {
ForEachGlobalTeardownObserver([&](GlobalTeardownObserver* et,
bool* aDoneOut) {
if (nsCOMPtr<nsISizeOfEventTarget> iSizeOf = do_QueryObject(et)) {
aWindowSizes.mDOMSizes.mDOMEventTargetsSize +=
iSizeOf->SizeOfEventTargetIncludingThis(
aWindowSizes.mState.mMallocSizeOf);
}
if (EventListenerManager* elm = et->GetExistingListenerManager()) {
aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
if (nsCOMPtr<DOMEventTargetHelper> helper = do_QueryObject(et)) {
if (EventListenerManager* elm = helper->GetExistingListenerManager()) {
aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
}
}
++aWindowSizes.mDOMEventTargetsCount;
});

View File

@ -7,6 +7,7 @@
#include "nsIGlobalObject.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/GlobalTeardownObserver.h"
#include "mozilla/Result.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/dom/BindingDeclarations.h"
@ -28,6 +29,7 @@ using mozilla::AutoSlowOperation;
using mozilla::CycleCollectedJSContext;
using mozilla::DOMEventTargetHelper;
using mozilla::ErrorResult;
using mozilla::GlobalTeardownObserver;
using mozilla::IgnoredErrorResult;
using mozilla::MallocSizeOf;
using mozilla::Maybe;
@ -67,8 +69,8 @@ bool nsIGlobalObject::IsScriptForbidden(JSObject* aCallback,
nsIGlobalObject::~nsIGlobalObject() {
UnlinkObjectsInGlobal();
DisconnectEventTargetObjects();
MOZ_DIAGNOSTIC_ASSERT(mEventTargetObjects.isEmpty());
DisconnectGlobalTeardownObservers();
MOZ_DIAGNOSTIC_ASSERT(mGlobalTeardownObservers.isEmpty());
}
nsIPrincipal* nsIGlobalObject::PrincipalOrNull() const {
@ -157,29 +159,31 @@ void nsIGlobalObject::TraverseObjectsInGlobal(
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mByteLengthQueuingStrategySizeFunction)
}
void nsIGlobalObject::AddEventTargetObject(DOMEventTargetHelper* aObject) {
void nsIGlobalObject::AddGlobalTeardownObserver(
GlobalTeardownObserver* aObject) {
MOZ_DIAGNOSTIC_ASSERT(aObject);
MOZ_ASSERT(!aObject->isInList());
mEventTargetObjects.insertBack(aObject);
mGlobalTeardownObservers.insertBack(aObject);
}
void nsIGlobalObject::RemoveEventTargetObject(DOMEventTargetHelper* aObject) {
void nsIGlobalObject::RemoveGlobalTeardownObserver(
GlobalTeardownObserver* aObject) {
MOZ_DIAGNOSTIC_ASSERT(aObject);
MOZ_ASSERT(aObject->isInList());
MOZ_ASSERT(aObject->GetOwnerGlobal() == this);
aObject->remove();
}
void nsIGlobalObject::ForEachEventTargetObject(
const std::function<void(DOMEventTargetHelper*, bool* aDoneOut)>& aFunc)
void nsIGlobalObject::ForEachGlobalTeardownObserver(
const std::function<void(GlobalTeardownObserver*, bool* aDoneOut)>& aFunc)
const {
// Protect against the function call triggering a mutation of the list
// while we are iterating by copying the DETH references to a temporary
// list.
AutoTArray<RefPtr<DOMEventTargetHelper>, 64> targetList;
for (const DOMEventTargetHelper* deth = mEventTargetObjects.getFirst(); deth;
deth = deth->getNext()) {
targetList.AppendElement(const_cast<DOMEventTargetHelper*>(deth));
AutoTArray<RefPtr<GlobalTeardownObserver>, 64> targetList;
for (const GlobalTeardownObserver* deth = mGlobalTeardownObservers.getFirst();
deth; deth = deth->getNext()) {
targetList.AppendElement(const_cast<GlobalTeardownObserver*>(deth));
}
// Iterate the target list and call the function on each one.
@ -197,14 +201,15 @@ void nsIGlobalObject::ForEachEventTargetObject(
}
}
void nsIGlobalObject::DisconnectEventTargetObjects() {
ForEachEventTargetObject([&](DOMEventTargetHelper* aTarget, bool* aDoneOut) {
aTarget->DisconnectFromOwner();
void nsIGlobalObject::DisconnectGlobalTeardownObservers() {
ForEachGlobalTeardownObserver(
[&](GlobalTeardownObserver* aTarget, bool* aDoneOut) {
aTarget->DisconnectFromOwner();
// Calling DisconnectFromOwner() should result in
// RemoveEventTargetObject() being called.
MOZ_DIAGNOSTIC_ASSERT(aTarget->GetOwnerGlobal() != this);
});
// Calling DisconnectFromOwner() should result in
// RemoveGlobalTeardownObserver() being called.
MOZ_DIAGNOSTIC_ASSERT(aTarget->GetOwnerGlobal() != this);
});
}
Maybe<ClientInfo> nsIGlobalObject::GetClientInfo() const {

View File

@ -36,6 +36,7 @@ class nsPIDOMWindowInner;
namespace mozilla {
class DOMEventTargetHelper;
class GlobalTeardownObserver;
template <typename V, typename E>
class Result;
enum class StorageAccess;
@ -71,8 +72,8 @@ class nsIGlobalObject : public nsISupports,
nsTArray<nsCString> mHostObjectURIs;
// Raw pointers to bound DETH objects. These are added by
// AddEventTargetObject().
mozilla::LinkedList<mozilla::DOMEventTargetHelper> mEventTargetObjects;
// AddGlobalTeardownObserver().
mozilla::LinkedList<mozilla::GlobalTeardownObserver> mGlobalTeardownObservers;
bool mIsDying;
bool mIsScriptForbidden;
@ -152,18 +153,18 @@ class nsIGlobalObject : public nsISupports,
void UnlinkObjectsInGlobal();
void TraverseObjectsInGlobal(nsCycleCollectionTraversalCallback& aCb);
// DETH objects must register themselves on the global when they
// GlobalTeardownObservers 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);
// called correctly. RemoveGlobalTeardownObserver() must be called
// before the GlobalTeardownObserver is destroyed.
void AddGlobalTeardownObserver(mozilla::GlobalTeardownObserver* aObject);
void RemoveGlobalTeardownObserver(mozilla::GlobalTeardownObserver* aObject);
// Iterate the registered DETH objects and call the given function
// Iterate the registered GlobalTeardownObservers and call the given function
// for each one.
void ForEachEventTargetObject(
const std::function<void(mozilla::DOMEventTargetHelper*, bool* aDoneOut)>&
aFunc) const;
void ForEachGlobalTeardownObserver(
const std::function<void(mozilla::GlobalTeardownObserver*,
bool* aDoneOut)>& aFunc) const;
virtual bool IsInSyncOperation() { return false; }
@ -282,7 +283,7 @@ class nsIGlobalObject : public nsISupports,
void StartForbiddingScript() { mIsScriptForbidden = true; }
void StopForbiddingScript() { mIsScriptForbidden = false; }
void DisconnectEventTargetObjects();
void DisconnectGlobalTeardownObservers();
size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aSizeOf) const;

View File

@ -556,7 +556,7 @@ NS_IMPL_ADDREF_INHERITED(OffscreenCanvas, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(OffscreenCanvas, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OffscreenCanvas)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
} // namespace mozilla::dom

View File

@ -24,8 +24,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper)
if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
char name[512];
nsAutoString uri;
if (tmp->mOwnerWindow && tmp->mOwnerWindow->GetExtantDoc()) {
Unused << tmp->mOwnerWindow->GetExtantDoc()->GetDocumentURI(uri);
if (tmp->GetOwner() && tmp->GetOwner()->GetExtantDoc()) {
Unused << tmp->GetOwner()->GetExtantDoc()->GetDocumentURI(uri);
}
nsXPCOMCycleCollectionParticipant* participant = nullptr;
@ -64,7 +64,8 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(DOMEventTargetHelper)
return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(tmp);
return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(
static_cast<dom::EventTarget*>(tmp));
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(DOMEventTargetHelper)
@ -73,55 +74,29 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMEventTargetHelper)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
NS_INTERFACE_MAP_ENTRY(GlobalTeardownObserver)
NS_INTERFACE_MAP_ENTRY(dom::EventTarget)
NS_INTERFACE_MAP_ENTRY(DOMEventTargetHelper)
NS_INTERFACE_MAP_ENTRY_CONCRETE(DOMEventTargetHelper)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper,
LastRelease())
DOMEventTargetHelper::DOMEventTargetHelper()
: mParentObject(nullptr),
mOwnerWindow(nullptr),
mHasOrHasHadOwnerWindow(false),
mIsKeptAlive(false) {}
DOMEventTargetHelper::DOMEventTargetHelper() = default;
DOMEventTargetHelper::DOMEventTargetHelper(nsPIDOMWindowInner* aWindow)
: mParentObject(nullptr),
mOwnerWindow(nullptr),
mHasOrHasHadOwnerWindow(false),
mIsKeptAlive(false) {
nsIGlobalObject* global = aWindow ? aWindow->AsGlobal() : nullptr;
BindToOwner(global);
}
: GlobalTeardownObserver(aWindow ? aWindow->AsGlobal() : nullptr) {}
DOMEventTargetHelper::DOMEventTargetHelper(nsIGlobalObject* aGlobalObject)
: mParentObject(nullptr),
mOwnerWindow(nullptr),
mHasOrHasHadOwnerWindow(false),
mIsKeptAlive(false) {
BindToOwner(aGlobalObject);
}
: GlobalTeardownObserver(aGlobalObject) {}
DOMEventTargetHelper::DOMEventTargetHelper(DOMEventTargetHelper* aOther)
: mParentObject(nullptr),
mOwnerWindow(nullptr),
mHasOrHasHadOwnerWindow(false),
mIsKeptAlive(false) {
if (!aOther) {
BindToOwner(static_cast<nsIGlobalObject*>(nullptr));
return;
}
BindToOwner(aOther->GetParentObject());
mHasOrHasHadOwnerWindow = aOther->HasOrHasHadOwner();
}
: GlobalTeardownObserver(aOther ? aOther->GetParentObject() : nullptr,
aOther ? aOther->HasOrHasHadOwner() : false) {}
DOMEventTargetHelper::~DOMEventTargetHelper() {
if (mParentObject) {
mParentObject->RemoveEventTargetObject(this);
}
if (mListenerManager) {
mListenerManager->Disconnect();
}
@ -129,11 +104,8 @@ DOMEventTargetHelper::~DOMEventTargetHelper() {
}
void DOMEventTargetHelper::DisconnectFromOwner() {
if (mParentObject) {
mParentObject->RemoveEventTargetObject(this);
}
mOwnerWindow = nullptr;
mParentObject = nullptr;
GlobalTeardownObserver::DisconnectFromOwner();
// Event listeners can't be handled anymore, so we can release them here.
if (mListenerManager) {
mListenerManager->Disconnect();
@ -173,8 +145,8 @@ bool DOMEventTargetHelper::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
bool DOMEventTargetHelper::DispatchEvent(Event& aEvent, CallerType aCallerType,
ErrorResult& aRv) {
nsEventStatus status = nsEventStatus_eIgnore;
nsresult rv = EventDispatcher::DispatchDOMEvent(this, nullptr, &aEvent,
nullptr, &status);
nsresult rv = EventDispatcher::DispatchDOMEvent(
static_cast<EventTarget*>(this), nullptr, &aEvent, nullptr, &status);
bool retval = !aEvent.DefaultPrevented(aCallerType);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
@ -282,45 +254,6 @@ void DOMEventTargetHelper::MaybeDontKeepAlive() {
}
}
void DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner) {
MOZ_ASSERT(!mParentObject);
if (aOwner) {
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;
}
}
}
nsresult DOMEventTargetHelper::CheckCurrentGlobalCorrectness() const {
NS_ENSURE_STATE(!mHasOrHasHadOwnerWindow || mOwnerWindow);
// Main-thread.
if (mOwnerWindow && !mOwnerWindow->IsCurrentInnerWindow()) {
return NS_ERROR_FAILURE;
}
if (NS_IsMainThread()) {
return NS_OK;
}
if (!mParentObject) {
return NS_ERROR_FAILURE;
}
if (mParentObject->IsDying()) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
bool DOMEventTargetHelper::HasListenersFor(const nsAString& aType) const {
return mListenerManager && mListenerManager->HasListenersFor(aType);
}

View File

@ -9,6 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/GlobalTeardownObserver.h"
#include "mozilla/LinkedList.h"
#include "mozilla/RefPtr.h"
#include "nsAtom.h"
@ -48,7 +49,7 @@ enum class CallerType : uint32_t;
}
class DOMEventTargetHelper : public dom::EventTarget,
public LinkedListElement<DOMEventTargetHelper> {
public GlobalTeardownObserver {
public:
DOMEventTargetHelper();
explicit DOMEventTargetHelper(nsPIDOMWindowInner* aWindow);
@ -56,7 +57,8 @@ class DOMEventTargetHelper : public dom::EventTarget,
explicit DOMEventTargetHelper(DOMEventTargetHelper* aOther);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_WRAPPERCACHE_CLASS(DOMEventTargetHelper)
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_WRAPPERCACHE_CLASS_AMBIGUOUS(
DOMEventTargetHelper, dom::EventTarget)
virtual EventListenerManager* GetExistingListenerManager() const override;
virtual EventListenerManager* GetOrCreateListenerManager() override;
@ -75,12 +77,8 @@ class DOMEventTargetHelper : public dom::EventTarget,
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOMEVENTTARGETHELPER_IID)
void GetParentObject(nsIScriptGlobalObject** aParentObject) {
if (mParentObject) {
CallQueryInterface(mParentObject, aParentObject);
} else {
*aParentObject = nullptr;
}
nsIGlobalObject* GetOwnerGlobal() const override {
return GlobalTeardownObserver::GetOwnerGlobal();
}
static DOMEventTargetHelper* FromSupports(nsISupports* aSupports) {
@ -107,19 +105,6 @@ class DOMEventTargetHelper : public dom::EventTarget,
return nsPIDOMWindowOuter::GetFromCurrentInner(GetOwner());
}
// A global permanently becomes invalid when DisconnectEventTargetObjects() is
// called. Normally this means:
// - For the main thread, when nsGlobalWindowInner::FreeInnerObjects is
// called.
// - For a worker thread, when clearing the main event queue. (Which we do
// slightly later than when the spec notionally calls for it to be done.)
//
// A global may also become temporarily invalid when:
// - For the main thread, if the window is no longer the WindowProxy's current
// inner window due to being placed in the bfcache.
nsresult CheckCurrentGlobalCorrectness() const;
nsPIDOMWindowInner* GetOwner() const { return mOwnerWindow; }
// Like GetOwner, but only returns non-null if the window being returned is
// current (in the "current document" sense of the HTML spec).
nsPIDOMWindowInner* GetWindowIfCurrent() const;
@ -127,10 +112,8 @@ class DOMEventTargetHelper : public dom::EventTarget,
// the current document of its browsing context. Will return null otherwise.
mozilla::dom::Document* GetDocumentIfCurrent() const;
virtual void DisconnectFromOwner();
void DisconnectFromOwner() override;
using EventTarget::GetParentObject;
nsIGlobalObject* GetOwnerGlobal() const final { return mParentObject; }
bool HasOrHasHadOwner() { return mHasOrHasHadOwnerWindow; }
virtual void EventListenerAdded(nsAtom* aType) override;
@ -162,21 +145,10 @@ class DOMEventTargetHelper : public dom::EventTarget,
void IgnoreKeepAliveIfHasListenersFor(nsAtom* aType);
void BindToOwner(nsIGlobalObject* aOwner);
private:
// 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.
nsPIDOMWindowInner* MOZ_NON_OWNING_REF mOwnerWindow;
bool mHasOrHasHadOwnerWindow;
nsTArray<RefPtr<nsAtom>> mKeepingAliveTypes;
bool mIsKeptAlive;
bool mIsKeptAlive = false;
};
NS_DEFINE_STATIC_IID_ACCESSOR(DOMEventTargetHelper, NS_DOMEVENTTARGETHELPER_IID)

View File

@ -818,7 +818,7 @@ void BlobURLProtocolHandler::Traverse(
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
aCallback, "BlobURLProtocolHandler mozilla::dom::DataInfo.mMediaSource");
aCallback.NoteXPCOMChild(res->mMediaSource);
aCallback.NoteXPCOMChild(static_cast<EventTarget*>(res->mMediaSource));
}
NS_IMPL_ISUPPORTS(BlobURLProtocolHandler, nsIProtocolHandler,

View File

@ -297,7 +297,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBRequest)
if (aIID.Equals(NS_GET_IID(mozilla::dom::detail::PrivateIDBRequest))) {
foundInterface = this;
foundInterface = static_cast<EventTarget*>(this);
} else
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)

View File

@ -3783,7 +3783,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChildMessageManager)
NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
NS_INTERFACE_MAP_ENTRY(ContentFrameMessageManager)
NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentFrameMessageManager)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)

View File

@ -112,7 +112,7 @@ NS_IMPL_ADDREF_INHERITED(DOMMediaStream, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(DOMMediaStream, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMMediaStream)
NS_INTERFACE_MAP_ENTRY(DOMMediaStream)
NS_INTERFACE_MAP_ENTRY_CONCRETE(DOMMediaStream)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
DOMMediaStream::DOMMediaStream(nsPIDOMWindowInner* aWindow)

View File

@ -173,8 +173,8 @@ nsresult ImageCapture::PostErrorEvent(uint16_t aErrorCode, nsresult aReason) {
}
}
RefPtr<ImageCaptureError> error =
new ImageCaptureError(this, aErrorCode, errorMsg);
RefPtr<ImageCaptureError> error = new ImageCaptureError(
static_cast<EventTarget*>(this), aErrorCode, errorMsg);
ImageCaptureErrorEventInit init;
init.mBubbles = false;

View File

@ -687,7 +687,7 @@ NS_IMPL_ADDREF_INHERITED(MediaSource, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(MediaSource, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaSource)
NS_INTERFACE_MAP_ENTRY(mozilla::dom::MediaSource)
NS_INTERFACE_MAP_ENTRY_CONCRETE(mozilla::dom::MediaSource)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
#undef MSE_DEBUG

View File

@ -841,8 +841,8 @@ class OnStateChangeTask final : public Runnable {
}
return nsContentUtils::DispatchTrustedEvent(
doc, static_cast<DOMEventTargetHelper*>(mAudioContext),
u"statechange"_ns, CanBubble::eNo, Cancelable::eNo);
doc, static_cast<EventTarget*>(mAudioContext), u"statechange"_ns,
CanBubble::eNo, Cancelable::eNo);
}
private:
@ -1192,7 +1192,7 @@ void AudioContext::ReportBlocked() {
AUTOPLAY_LOG("Dispatch `blocked` event for AudioContext %p",
self.get());
nsContentUtils::DispatchTrustedEvent(
doc, static_cast<DOMEventTargetHelper*>(self), u"blocked"_ns,
doc, static_cast<EventTarget*>(self), u"blocked"_ns,
CanBubble::eNo, Cancelable::eNo);
});
Dispatch(r.forget());

View File

@ -32,7 +32,7 @@ JSObject* SpeechRecognitionAlternative::WrapObject(
}
nsISupports* SpeechRecognitionAlternative::GetParentObject() const {
return static_cast<DOMEventTargetHelper*>(mParent.get());
return static_cast<EventTarget*>(mParent.get());
}
void SpeechRecognitionAlternative::GetTranscript(nsString& aRetVal) const {

View File

@ -30,7 +30,7 @@ JSObject* SpeechRecognitionResult::WrapObject(
}
nsISupports* SpeechRecognitionResult::GetParentObject() const {
return static_cast<DOMEventTargetHelper*>(mParent.get());
return static_cast<EventTarget*>(mParent.get());
}
already_AddRefed<SpeechRecognitionAlternative>

View File

@ -28,7 +28,7 @@ SpeechRecognitionResultList::SpeechRecognitionResultList(
SpeechRecognitionResultList::~SpeechRecognitionResultList() = default;
nsISupports* SpeechRecognitionResultList::GetParentObject() const {
return static_cast<DOMEventTargetHelper*>(mParent.get());
return static_cast<EventTarget*>(mParent.get());
}
JSObject* SpeechRecognitionResultList::WrapObject(

View File

@ -131,7 +131,8 @@ already_AddRefed<DocumentFragment> TextTrackCue::GetCueAsHTML() {
}
RefPtr<DocumentFragment> frag;
sParserWrapper->ConvertCueToDOMTree(window, this, getter_AddRefs(frag));
sParserWrapper->ConvertCueToDOMTree(window, static_cast<EventTarget*>(this),
getter_AddRefs(frag));
if (!frag) {
return mDocument->CreateDocumentFragment();
}

View File

@ -85,7 +85,7 @@ NS_IMPL_RELEASE_INHERITED(PerformanceMainThread, Performance)
// QueryInterface implementation for PerformanceMainThread
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceMainThread)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
NS_INTERFACE_MAP_END_INHERITING(Performance)
PerformanceMainThread::PerformanceMainThread(nsPIDOMWindowInner* aWindow,

View File

@ -130,7 +130,7 @@ NS_IMPL_ADDREF_INHERITED(ServiceWorker, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(ServiceWorker, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorker)
NS_INTERFACE_MAP_ENTRY(ServiceWorker)
NS_INTERFACE_MAP_ENTRY_CONCRETE(ServiceWorker)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
JSObject* ServiceWorker::WrapObject(JSContext* aCx,

View File

@ -37,7 +37,7 @@ NS_IMPL_ADDREF_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerRegistration)
NS_INTERFACE_MAP_ENTRY(ServiceWorkerRegistration)
NS_INTERFACE_MAP_ENTRY_CONCRETE(ServiceWorkerRegistration)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
namespace {

View File

@ -7,6 +7,7 @@
#ifndef mozilla_dom_UnderlyingSourceCallbackHelpers_h
#define mozilla_dom_UnderlyingSourceCallbackHelpers_h
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/UnderlyingSourceBinding.h"

View File

@ -634,7 +634,7 @@ NS_IMPL_RELEASE_INHERITED(VRDisplay, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VRDisplay)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, DOMEventTargetHelper)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_CLASS(VRFrameData)

View File

@ -526,7 +526,8 @@ RefPtr<XRViewerPose> XRSession::PooledViewerPose(
pose->Transform()->Update(aTransform);
pose->SetEmulatedPosition(aEmulatedPosition);
} else {
RefPtr<XRRigidTransform> transform = new XRRigidTransform(this, aTransform);
RefPtr<XRRigidTransform> transform =
new XRRigidTransform(static_cast<EventTarget*>(this), aTransform);
nsTArray<RefPtr<XRView>> views;
if (IsImmersive()) {
views.AppendElement(new XRView(GetParentObject(), XREye::Left));
@ -534,7 +535,8 @@ RefPtr<XRViewerPose> XRSession::PooledViewerPose(
} else {
views.AppendElement(new XRView(GetParentObject(), XREye::None));
}
pose = new XRViewerPose(this, transform, aEmulatedPosition, views);
pose = new XRViewerPose(static_cast<EventTarget*>(this), transform,
aEmulatedPosition, views);
mViewerPosePool.AppendElement(pose);
}

View File

@ -3943,7 +3943,7 @@ void WorkerPrivate::ClearMainEventQueue(WorkerRanOrNot aRanOrNot) {
// It's appropriate to disconnect event targets at the point that it's no
// longer possible for new tasks to be dispatched at the global, and this is
// that point.
globalScope->DisconnectEventTargetObjects();
globalScope->DisconnectGlobalTeardownObservers();
globalScope->WorkerPrivateSaysForbidScript();
}

View File

@ -824,15 +824,16 @@ WorkerGlobalScope::GetServiceWorkerRegistration(
const ServiceWorkerRegistrationDescriptor& aDescriptor) const {
AssertIsOnWorkerThread();
RefPtr<ServiceWorkerRegistration> ref;
ForEachEventTargetObject([&](DOMEventTargetHelper* aTarget, bool* aDoneOut) {
RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aTarget);
if (!swr || !swr->MatchesDescriptor(aDescriptor)) {
return;
}
ForEachGlobalTeardownObserver(
[&](GlobalTeardownObserver* aObserver, bool* aDoneOut) {
RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aObserver);
if (!swr || !swr->MatchesDescriptor(aDescriptor)) {
return;
}
ref = std::move(swr);
*aDoneOut = true;
});
ref = std::move(swr);
*aDoneOut = true;
});
return ref;
}

View File

@ -113,7 +113,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(ChannelWrapper::ChannelWrapperStub)
NS_IMPL_CYCLE_COLLECTION(ChannelWrapper::ChannelWrapperStub, mChannelWrapper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChannelWrapper::ChannelWrapperStub)
NS_INTERFACE_MAP_ENTRY_TEAROFF(ChannelWrapper, mChannelWrapper)
NS_INTERFACE_MAP_ENTRY_TEAROFF_AMBIGUOUS(ChannelWrapper, EventTarget,
mChannelWrapper)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
@ -1249,7 +1250,7 @@ JSObject* ChannelWrapper::WrapObject(JSContext* aCx,
NS_IMPL_CYCLE_COLLECTION_CLASS(ChannelWrapper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChannelWrapper)
NS_INTERFACE_MAP_ENTRY(ChannelWrapper)
NS_INTERFACE_MAP_ENTRY_CONCRETE(ChannelWrapper)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ChannelWrapper,