Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 "nsGlobalWindowInner.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdint>
#include <new>
#include <type_traits>
#include <utility>
#include "AudioChannelService.h"
#include "AutoplayPolicy.h"
#include "Crypto.h"
#include "MainThreadUtils.h"
#include "Navigator.h"
#include "PaintWorkletImpl.h"
#include "SessionStorageCache.h"
#include "Units.h"
#include "VRManagerChild.h"
#include "WindowDestroyedEvent.h"
#include "WindowNamedPropertiesHandler.h"
#include "js/ComparisonOperators.h"
#include "js/CompileOptions.h"
#include "js/friend/PerformanceHint.h"
#include "js/Id.h"
#include "js/loader/LoadedScript.h"
#include "js/PropertyAndElement.h" // JS_DefineProperty, JS_GetProperty
#include "js/PropertyDescriptor.h"
#include "js/RealmOptions.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "js/Warnings.h"
#include "js/shadow/String.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "mozIDOMWindow.h"
#include "moz_external_vr.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/ArrayIterator.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/BaseProfilerMarkersPrerequisites.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/BounceTrackingStorageObserver.h"
#include "mozilla/CallState.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventQueue.h"
#include "mozilla/ExtensionPolicyService.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/FlushType.h"
#include "mozilla/Likely.h"
#include "mozilla/LinkedList.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Logging.h"
#include "mozilla/MacroForEach.h"
#include "mozilla/Maybe.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/PermissionDelegateHandler.h"
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/ProcessHangMonitor.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Result.h"
#include "mozilla/ScrollTypes.h"
#include "mozilla/Components.h"
#include "mozilla/SizeOfState.h"
#include "mozilla/Span.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPrefs_docshell.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_extensions.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TelemetryHistogramEnums.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/AudioContext.h"
#include "mozilla/dom/AutoEntryScript.h"
#include "mozilla/dom/BarProps.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/CSPEvalChecker.h"
#include "mozilla/dom/CallbackDebuggerNotification.h"
#include "mozilla/dom/ChromeMessageBroadcaster.h"
#include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/ClientManager.h"
#include "mozilla/dom/ClientSource.h"
#include "mozilla/dom/ClientState.h"
#include "mozilla/dom/ClientsBinding.h"
#include "mozilla/dom/Console.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentFrameMessageManager.h"
#include "mozilla/dom/ContentMediaController.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/DebuggerNotification.h"
#include "mozilla/dom/DebuggerNotificationBinding.h"
#include "mozilla/dom/DebuggerNotificationManager.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/External.h"
#include "mozilla/dom/Fetch.h"
#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/GamepadHandle.h"
#include "mozilla/dom/GamepadManager.h"
#include "mozilla/dom/HashChangeEvent.h"
#include "mozilla/dom/HashChangeEventBinding.h"
#include "mozilla/dom/IDBFactory.h"
#include "mozilla/dom/IdleRequest.h"
#include "mozilla/dom/ImageBitmap.h"
#include "mozilla/dom/ImageBitmapSource.h"
#include "mozilla/dom/InstallTriggerBinding.h"
#include "mozilla/dom/IntlUtils.h"
#include "mozilla/dom/JSExecutionContext.h"
#include "mozilla/dom/LSObject.h"
#include "mozilla/dom/LocalStorage.h"
#include "mozilla/dom/LocalStorageCommon.h"
#include "mozilla/dom/Location.h"
#include "mozilla/dom/MediaDevices.h"
#include "mozilla/dom/MediaKeys.h"
#include "mozilla/dom/NavigatorBinding.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/dom/PartitionedLocalStorage.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/PerformanceMainThread.h"
#include "mozilla/dom/PopStateEvent.h"
#include "mozilla/dom/PopStateEventBinding.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/PrimitiveConversions.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/RootedDictionary.h"
#include "mozilla/dom/WebTaskSchedulerMainThread.h"
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ServiceWorker.h"
#include "mozilla/dom/ServiceWorkerDescriptor.h"
#include "mozilla/dom/ServiceWorkerRegistration.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/dom/SharedWorker.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/dom/StorageNotifierService.h"
#include "mozilla/dom/StorageUtils.h"
#include "mozilla/dom/TabMessageTypes.h"
#include "mozilla/dom/Timeout.h"
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/TimeoutManager.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/TrustedTypePolicyFactory.h"
#include "mozilla/dom/VRDisplay.h"
#include "mozilla/dom/VRDisplayEvent.h"
#include "mozilla/dom/VRDisplayEventBinding.h"
#include "mozilla/dom/VREventObserver.h"
#include "mozilla/dom/VisualViewport.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/Worklet.h"
#include "mozilla/dom/XRPermissionRequest.h"
#include "mozilla/dom/cache/CacheStorage.h"
#include "mozilla/dom/cache/Types.h"
#include "mozilla/glean/bindings/Glean.h"
#include "mozilla/glean/bindings/GleanPings.h"
#include "mozilla/extensions/WebExtensionPolicy.h"
#include "mozilla/fallible.h"
#include "mozilla/gfx/BasePoint.h"
#include "mozilla/gfx/BaseRect.h"
#include "mozilla/gfx/BaseSize.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/intl/LocaleService.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/net/CookieJarSettings.h"
#include "nsAtom.h"
#include "nsBaseHashtable.h"
#include "nsCCUncollectableMarker.h"
#include "nsCOMPtr.h"
#include "nsCRT.h"
#include "nsCRTGlue.h"
#include "nsCanvasFrame.h"
#include "nsCharTraits.h"
#include "nsCheapSets.h"
#include "nsContentUtils.h"
#include "nsCoord.h"
#include "nsCycleCollectionNoteChild.h"
#include "nsCycleCollectionTraversalCallback.h"
#include "nsDOMNavigationTiming.h"
#include "nsDebug.h"
#include "nsDeviceContext.h"
#include "nsDocShell.h"
#include "nsFocusManager.h"
#include "nsFrameMessageManager.h"
#include "nsGkAtoms.h"
#include "nsGlobalWindowOuter.h"
#include "nsHashKeys.h"
#include "nsHistory.h"
#include "nsIAddonPolicyService.h"
#include "nsIArray.h"
#include "nsIBaseWindow.h"
#include "nsIBrowserChild.h"
#include "nsICancelableRunnable.h"
#include "nsIChannel.h"
#include "nsIClipboard.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIControllers.h"
#include "nsICookieJarSettings.h"
#include "nsICookieService.h"
#include "nsID.h"
#include "nsIDOMStorageManager.h"
#include "nsIDeviceSensors.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDocumentLoader.h"
#include "nsIDragService.h"
#include "nsIFocusManager.h"
#include "nsIFrame.h"
#include "nsIGlobalObject.h"
#include "nsIIOService.h"
#include "nsIIdleRunnable.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadContext.h"
#include "nsILoadGroup.h"
#include "nsILoadInfo.h"
#include "nsINamed.h"
#include "nsINode.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIPermission.h"
#include "nsIPermissionManager.h"
#include "nsIPrefBranch.h"
#include "nsIPrincipal.h"
#include "nsIPrompt.h"
#include "nsIRunnable.h"
#include "nsIScreen.h"
#include "nsIScreenManager.h"
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScrollableFrame.h"
#include "nsISerialEventTarget.h"
#include "nsISimpleEnumerator.h"
#include "nsISizeOfEventTarget.h"
#include "nsISlowScriptDebug.h"
#include "nsISupportsUtils.h"
#include "nsIThread.h"
#include "nsITimedChannel.h"
#include "nsIURI.h"
#include "nsIWeakReference.h"
#include "nsIWebBrowserChrome.h"
#include "nsIWebNavigation.h"
#include "nsIWebProgressListener.h"
#include "nsIWidget.h"
#include "nsIWidgetListener.h"
#include "nsIXULRuntime.h"
#include "nsJSPrincipals.h"
#include "nsJSUtils.h"
#include "nsLayoutStatics.h"
#include "nsLiteralString.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsPIDOMWindowInlines.h"
#include "nsPIWindowRoot.h"
#include "nsPoint.h"
#include "nsPresContext.h"
#include "nsQueryObject.h"
#include "nsSandboxFlags.h"
#include "nsScreen.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsStringFlags.h"
#include "nsStringFwd.h"
#include "nsTArray.h"
#include "nsTLiteralString.h"
#include "nsTObserverArray.h"
#include "nsTStringRepr.h"
#include "nsThreadUtils.h"
#include "nsWeakReference.h"
#include "nsWindowMemoryReporter.h"
#include "nsWindowSizes.h"
#include "nsWrapperCache.h"
#include "nsWrapperCacheInlines.h"
#include "nsXULAppAPI.h"
#include "nsrootidl.h"
#include "prclist.h"
#include "prtypes.h"
#include "xpcprivate.h"
#include "xpcpublic.h"
#include "nsIDOMXULControlElement.h"
#ifdef NS_PRINTING
# include "nsIPrintSettings.h"
#endif
#ifdef MOZ_WEBSPEECH
# include "mozilla/dom/SpeechSynthesis.h"
#endif
#ifdef ANDROID
# include <android/log.h>
#endif
#ifdef XP_WIN
# include "mozilla/Debug.h"
# include <process.h>
# define getpid _getpid
#else
# include <unistd.h> // for getpid()
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using mozilla::TimeDuration;
using mozilla::TimeStamp;
using mozilla::dom::GamepadHandle;
using mozilla::dom::cache::CacheStorage;
#define FORWARD_TO_OUTER(method, args, err_rval) \
PR_BEGIN_MACRO \
RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal(); \
if (!HasActiveDocument()) { \
NS_WARNING(outer ? "Inner window does not have active document." \
: "No outer window available!"); \
return err_rval; \
} \
return outer->method args; \
PR_END_MACRO
static nsGlobalWindowOuter* GetOuterWindowForForwarding(
nsGlobalWindowInner* aInner, ErrorResult& aError) {
nsGlobalWindowOuter* outer = aInner->GetOuterWindowInternal();
if (MOZ_LIKELY(aInner->HasActiveDocument())) {
return outer;
}
if (!outer) {
NS_WARNING("No outer window available!");
aError.Throw(NS_ERROR_NOT_INITIALIZED);
} else {
aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO);
}
return nullptr;
}
#define FORWARD_TO_OUTER_OR_THROW(method, args, rv, err_rval) \
PR_BEGIN_MACRO \
RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowForForwarding(this, rv); \
if (MOZ_LIKELY(outer)) { \
return outer->method args; \
} \
return err_rval; \
PR_END_MACRO
#define FORWARD_TO_OUTER_VOID(method, args) \
PR_BEGIN_MACRO \
RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal(); \
if (!HasActiveDocument()) { \
NS_WARNING(outer ? "Inner window does not have active document." \
: "No outer window available!"); \
return; \
} \
outer->method args; \
return; \
PR_END_MACRO
#define ENSURE_ACTIVE_DOCUMENT(errorresult, err_rval) \
PR_BEGIN_MACRO \
if (MOZ_UNLIKELY(!HasActiveDocument())) { \
aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \
return err_rval; \
} \
PR_END_MACRO
#define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
#define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
#define PERMISSION_CHANGED_TOPIC "perm-changed"
static LazyLogModule gDOMLeakPRLogInner("DOMLeakInner");
extern mozilla::LazyLogModule gTimeoutLog;
#ifdef DEBUG
static LazyLogModule gDocShellAndDOMWindowLeakLogging(
"DocShellAndDOMWindowLeak");
#endif
static FILE* gDumpFile = nullptr;
nsGlobalWindowInner::InnerWindowByIdTable*
nsGlobalWindowInner::sInnerWindowsById = nullptr;
bool nsGlobalWindowInner::sDragServiceDisabled = false;
bool nsGlobalWindowInner::sMouseDown = false;
/**
* An indirect observer object that means we don't have to implement nsIObserver
* on nsGlobalWindow, where any script could see it.
*/
class nsGlobalWindowObserver final : public nsIObserver,
public nsIInterfaceRequestor,
public StorageNotificationObserver {
public:
explicit nsGlobalWindowObserver(nsGlobalWindowInner* aWindow)
: mWindow(aWindow) {}
NS_DECL_ISUPPORTS
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) override {
if (!mWindow) return NS_OK;
return mWindow->Observe(aSubject, aTopic, aData);
}
void Forget() { mWindow = nullptr; }
NS_IMETHOD GetInterface(const nsIID& aIID, void** aResult) override {
if (mWindow && aIID.Equals(NS_GET_IID(nsIDOMWindow)) && mWindow) {
return mWindow->QueryInterface(aIID, aResult);
}
return NS_NOINTERFACE;
}
void ObserveStorageNotification(StorageEvent* aEvent,
const char16_t* aStorageType,
bool aPrivateBrowsing) override {
if (mWindow) {
mWindow->ObserveStorageNotification(aEvent, aStorageType,
aPrivateBrowsing);
}
}
nsIPrincipal* GetEffectiveCookiePrincipal() const override {
return mWindow ? mWindow->GetEffectiveCookiePrincipal() : nullptr;
}
nsIPrincipal* GetEffectiveStoragePrincipal() const override {
return mWindow ? mWindow->GetEffectiveStoragePrincipal() : nullptr;
}
bool IsPrivateBrowsing() const override {
return mWindow ? mWindow->IsPrivateBrowsing() : false;
}
nsIEventTarget* GetEventTarget() const override {
return mWindow ? mWindow->SerialEventTarget() : nullptr;
}
private:
~nsGlobalWindowObserver() = default;
// This reference is non-owning and safe because it's cleared by
// nsGlobalWindowInner::FreeInnerObjects().
nsGlobalWindowInner* MOZ_NON_OWNING_REF mWindow;
};
NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)
class IdleRequestExecutor;
class IdleRequestExecutorTimeoutHandler final : public TimeoutHandler {
public:
explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor* aExecutor)
: mExecutor(aExecutor) {}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestExecutorTimeoutHandler)
bool Call(const char* /* unused */) override;
private:
~IdleRequestExecutorTimeoutHandler() override = default;
RefPtr<IdleRequestExecutor> mExecutor;
};
NS_IMPL_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler, mExecutor)
NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutorTimeoutHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutorTimeoutHandler)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
class IdleRequestExecutor final : public nsIRunnable,
public nsICancelableRunnable,
public nsINamed,
public nsIIdleRunnable {
public:
explicit IdleRequestExecutor(nsGlobalWindowInner* aWindow)
: mDispatched(false), mDeadline(TimeStamp::Now()), mWindow(aWindow) {
MOZ_DIAGNOSTIC_ASSERT(mWindow);
mIdlePeriodLimit = {mDeadline, mWindow->LastIdleRequestHandle()};
mDelayedExecutorDispatcher = new IdleRequestExecutorTimeoutHandler(this);
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor, nsIRunnable)
NS_DECL_NSIRUNNABLE
NS_DECL_NSINAMED
nsresult Cancel() override;
void SetDeadline(TimeStamp aDeadline) override;
bool IsCancelled() const { return !mWindow || mWindow->IsDying(); }
// Checks if aRequest shouldn't execute in the current idle period
// since it has been queued from a chained call to
// requestIdleCallback from within a running idle callback.
bool IneligibleForCurrentIdlePeriod(IdleRequest* aRequest) const {
return aRequest->Handle() >= mIdlePeriodLimit.mLastRequestIdInIdlePeriod &&
TimeStamp::Now() <= mIdlePeriodLimit.mEndOfIdlePeriod;
}
void MaybeUpdateIdlePeriodLimit();
// Maybe dispatch the IdleRequestExecutor. MabyeDispatch will
// schedule a delayed dispatch if the associated window is in the
// background or if given a time to wait until dispatching.
void MaybeDispatch(TimeStamp aDelayUntil = TimeStamp());
void ScheduleDispatch();
private:
struct IdlePeriodLimit {
TimeStamp mEndOfIdlePeriod;
uint32_t mLastRequestIdInIdlePeriod;
};
void DelayedDispatch(uint32_t aDelay);
~IdleRequestExecutor() override = default;
bool mDispatched;
TimeStamp mDeadline;
IdlePeriodLimit mIdlePeriodLimit;
RefPtr<nsGlobalWindowInner> mWindow;
// The timeout handler responsible for dispatching this executor in
// the case of immediate dispatch to the idle queue isn't
// desirable. This is used if we've dispatched all idle callbacks
// that are allowed to run in the current idle period, or if the
// associated window is currently in the background.
RefPtr<TimeoutHandler> mDelayedExecutorDispatcher;
// If not Nothing() then this value is the handle to the currently
// scheduled delayed executor dispatcher. This is needed to be able
// to cancel the timeout handler in case of the executor being
// cancelled.
Maybe<int32_t> mDelayedExecutorHandle;
};
NS_IMPL_CYCLE_COLLECTION(IdleRequestExecutor, mWindow,
mDelayedExecutorDispatcher)
NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor)
NS_INTERFACE_MAP_ENTRY(nsIRunnable)
NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable)
NS_INTERFACE_MAP_ENTRY(nsINamed)
NS_INTERFACE_MAP_ENTRY(nsIIdleRunnable)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable)
NS_INTERFACE_MAP_END
NS_IMETHODIMP
IdleRequestExecutor::GetName(nsACString& aName) {
aName.AssignLiteral("IdleRequestExecutor");
return NS_OK;
}
// MOZ_CAN_RUN_SCRIPT_BOUNDARY until nsIRunnable::Run is MOZ_CAN_RUN_SCRIPT.
// See bug 1535398.
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP IdleRequestExecutor::Run() {
MOZ_ASSERT(NS_IsMainThread());
mDispatched = false;
if (mWindow) {
RefPtr<nsGlobalWindowInner> window(mWindow);
window->ExecuteIdleRequest(mDeadline);
}
return NS_OK;
}
nsresult IdleRequestExecutor::Cancel() {
MOZ_ASSERT(NS_IsMainThread());
if (mDelayedExecutorHandle && mWindow) {
mWindow->TimeoutManager().ClearTimeout(
mDelayedExecutorHandle.value(), Timeout::Reason::eIdleCallbackTimeout);
}
mWindow = nullptr;
return NS_OK;
}
void IdleRequestExecutor::SetDeadline(TimeStamp aDeadline) {
MOZ_ASSERT(NS_IsMainThread());
if (!mWindow) {
return;
}
mDeadline = aDeadline;
}
void IdleRequestExecutor::MaybeUpdateIdlePeriodLimit() {
if (TimeStamp::Now() > mIdlePeriodLimit.mEndOfIdlePeriod) {
mIdlePeriodLimit = {mDeadline, mWindow->LastIdleRequestHandle()};
}
}
void IdleRequestExecutor::MaybeDispatch(TimeStamp aDelayUntil) {
// If we've already dispatched the executor we don't want to do it
// again. Also, if we've called IdleRequestExecutor::Cancel mWindow
// will be null, which indicates that we shouldn't dispatch this
// executor either.
if (mDispatched || IsCancelled()) {
return;
}
mDispatched = true;
nsPIDOMWindowOuter* outer = mWindow->GetOuterWindow();
if (outer && outer->IsBackground()) {
// Set a timeout handler with a timeout of 0 ms to throttle idle
// callback requests coming from a backround window using
// background timeout throttling.
DelayedDispatch(0);
return;
}
TimeStamp now = TimeStamp::Now();
if (!aDelayUntil || aDelayUntil < now) {
ScheduleDispatch();
return;
}
TimeDuration delay = aDelayUntil - now;
DelayedDispatch(static_cast<uint32_t>(delay.ToMilliseconds()));
}
void IdleRequestExecutor::ScheduleDispatch() {
MOZ_ASSERT(mWindow);
mDelayedExecutorHandle = Nothing();
RefPtr<IdleRequestExecutor> request = this;
NS_DispatchToCurrentThreadQueue(request.forget(), EventQueuePriority::Idle);
}
void IdleRequestExecutor::DelayedDispatch(uint32_t aDelay) {
MOZ_ASSERT(mWindow);
MOZ_ASSERT(mDelayedExecutorHandle.isNothing());
int32_t handle;
mWindow->TimeoutManager().SetTimeout(
mDelayedExecutorDispatcher, aDelay, false,
Timeout::Reason::eIdleCallbackTimeout, &handle);
mDelayedExecutorHandle = Some(handle);
}
bool IdleRequestExecutorTimeoutHandler::Call(const char* /* unused */) {
if (!mExecutor->IsCancelled()) {
mExecutor->ScheduleDispatch();
}
return true;
}
void nsGlobalWindowInner::ScheduleIdleRequestDispatch() {
AssertIsOnMainThread();
if (!mIdleRequestExecutor) {
mIdleRequestExecutor = new IdleRequestExecutor(this);
}
mIdleRequestExecutor->MaybeDispatch();
}
void nsGlobalWindowInner::SuspendIdleRequests() {
if (mIdleRequestExecutor) {
mIdleRequestExecutor->Cancel();
mIdleRequestExecutor = nullptr;
}
}
void nsGlobalWindowInner::ResumeIdleRequests() {
MOZ_ASSERT(!mIdleRequestExecutor);
ScheduleIdleRequestDispatch();
}
void nsGlobalWindowInner::RemoveIdleCallback(
mozilla::dom::IdleRequest* aRequest) {
AssertIsOnMainThread();
if (aRequest->HasTimeout()) {
mTimeoutManager->ClearTimeout(aRequest->GetTimeoutHandle(),
Timeout::Reason::eIdleCallbackTimeout);
}
aRequest->removeFrom(mIdleRequestCallbacks);
}
void nsGlobalWindowInner::RunIdleRequest(IdleRequest* aRequest,
DOMHighResTimeStamp aDeadline,
bool aDidTimeout) {
AssertIsOnMainThread();
// XXXbz Do we still need this RefPtr? MOZ_CAN_RUN_SCRIPT should
// guarantee that caller is holding a strong ref on the stack.
RefPtr<IdleRequest> request(aRequest);
RemoveIdleCallback(request);
request->IdleRun(this, aDeadline, aDidTimeout);
}
void nsGlobalWindowInner::ExecuteIdleRequest(TimeStamp aDeadline) {
AssertIsOnMainThread();
RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
if (!request) {
// There are no more idle requests, so stop scheduling idle
// request callbacks.
return;
}
// If the request that we're trying to execute has been queued
// during the current idle period, then dispatch it again at the end
// of the idle period.
if (mIdleRequestExecutor->IneligibleForCurrentIdlePeriod(request)) {
mIdleRequestExecutor->MaybeDispatch(aDeadline);
return;
}
DOMHighResTimeStamp deadline = 0.0;
if (Performance* perf = GetPerformance()) {
deadline = perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline);
}
mIdleRequestExecutor->MaybeUpdateIdlePeriodLimit();
RunIdleRequest(request, deadline, false);
// Running the idle callback could've suspended the window, in which
// case mIdleRequestExecutor will be null.
if (mIdleRequestExecutor) {
mIdleRequestExecutor->MaybeDispatch();
}
}
class IdleRequestTimeoutHandler final : public TimeoutHandler {
public:
IdleRequestTimeoutHandler(JSContext* aCx, IdleRequest* aIdleRequest,
nsPIDOMWindowInner* aWindow)
: TimeoutHandler(aCx), mIdleRequest(aIdleRequest), mWindow(aWindow) {}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestTimeoutHandler)
MOZ_CAN_RUN_SCRIPT bool Call(const char* /* unused */) override {
RefPtr<nsGlobalWindowInner> window(nsGlobalWindowInner::Cast(mWindow));
RefPtr<IdleRequest> request(mIdleRequest);
window->RunIdleRequest(request, 0.0, true);
return true;
}
private:
~IdleRequestTimeoutHandler() override = default;
RefPtr<IdleRequest> mIdleRequest;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
};
NS_IMPL_CYCLE_COLLECTION(IdleRequestTimeoutHandler, mIdleRequest, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestTimeoutHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestTimeoutHandler)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
uint32_t nsGlobalWindowInner::RequestIdleCallback(
JSContext* aCx, IdleRequestCallback& aCallback,
const IdleRequestOptions& aOptions, ErrorResult& aError) {
AssertIsOnMainThread();
if (IsDying()) {
return 0;
}
uint32_t handle = mIdleRequestCallbackCounter++;
RefPtr<IdleRequest> request = new IdleRequest(&aCallback, handle);
if (aOptions.mTimeout.WasPassed()) {
int32_t timeoutHandle;
RefPtr<TimeoutHandler> handler(
new IdleRequestTimeoutHandler(aCx, request, this));
nsresult rv = mTimeoutManager->SetTimeout(
handler, aOptions.mTimeout.Value(), false,
Timeout::Reason::eIdleCallbackTimeout, &timeoutHandle);
if (NS_WARN_IF(NS_FAILED(rv))) {
return 0;
}
request->SetTimeoutHandle(timeoutHandle);
}
mIdleRequestCallbacks.insertBack(request);
if (!IsSuspended()) {
ScheduleIdleRequestDispatch();
}
return handle;
}
void nsGlobalWindowInner::CancelIdleCallback(uint32_t aHandle) {
for (IdleRequest* r : mIdleRequestCallbacks) {
if (r->Handle() == aHandle) {
RemoveIdleCallback(r);
break;
}
}
}
void nsGlobalWindowInner::DisableIdleCallbackRequests() {
if (mIdleRequestExecutor) {
mIdleRequestExecutor->Cancel();
mIdleRequestExecutor = nullptr;
}
while (!mIdleRequestCallbacks.isEmpty()) {
RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
RemoveIdleCallback(request);
}
}
bool nsGlobalWindowInner::IsBackgroundInternal() const {
return !mOuterWindow || mOuterWindow->IsBackground();
}
class PromiseDocumentFlushedResolver final {
public:
PromiseDocumentFlushedResolver(Promise* aPromise,
PromiseDocumentFlushedCallback& aCallback)
: mPromise(aPromise), mCallback(&aCallback) {}
virtual ~PromiseDocumentFlushedResolver() = default;
void Call() {
nsMutationGuard guard;
ErrorResult error;
JS::Rooted<JS::Value> returnVal(RootingCx());
mCallback->Call(&returnVal, error);
if (error.Failed()) {
mPromise->MaybeReject(std::move(error));
} else if (guard.Mutated(0)) {
// Something within the callback mutated the DOM.
mPromise->MaybeRejectWithNoModificationAllowedError(
"DOM mutated from promiseDocumentFlushed callbacks");
} else {
mPromise->MaybeResolve(returnVal);
}
}
RefPtr<Promise> mPromise;
RefPtr<PromiseDocumentFlushedCallback> mCallback;
};
//*****************************************************************************
//*** nsGlobalWindowInner: Object Management
//*****************************************************************************
nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow,
WindowGlobalChild* aActor)
: nsPIDOMWindowInner(aOuterWindow, aActor),
mHasOrientationChangeListeners(false),
mWasOffline(false),
mHasHadSlowScript(false),
mIsChrome(false),
mCleanMessageManager(false),
mNeedsFocus(true),
mHasFocus(false),
mFocusByKeyOccurred(false),
mDidFireDocElemInserted(false),
mHasGamepad(false),
mHasXRSession(false),
mHasVRDisplayActivateEvents(false),
mXRRuntimeDetectionInFlight(false),
mXRPermissionRequestInFlight(false),
mXRPermissionGranted(false),
mWasCurrentInnerWindow(false),
mHasSeenGamepadInput(false),
mHintedWasLoading(false),
mHasOpenedExternalProtocolFrame(false),
mScrollMarksOnHScrollbar(false),
mStorageAllowedReasonCache(0),
mSuspendDepth(0),
mFreezeDepth(0),
#ifdef DEBUG
mSerial(0),
#endif
mFocusMethod(0),
mIdleRequestCallbackCounter(1),
mIdleRequestExecutor(nullptr),
mObservingRefresh(false),
mIteratingDocumentFlushedResolvers(false),
mCanSkipCCGeneration(0) {
mIsInnerWindow = true;
AssertIsOnMainThread();
SetIsOnMainThread();
nsLayoutStatics::AddRef();
// Initialize the PRCList (this).
PR_INIT_CLIST(this);
// add this inner window to the outer window list of inners.
PR_INSERT_AFTER(this, aOuterWindow);
mTimeoutManager = MakeUnique<dom::TimeoutManager>(
*this, StaticPrefs::dom_timeout_max_idle_defer_ms());
mObserver = new nsGlobalWindowObserver(this);
if (nsCOMPtr<nsIObserverService> os = services::GetObserverService()) {
// Watch for online/offline status changes so we can fire events. Use
// a strong reference.
os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, false);
os->AddObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC, false);
os->AddObserver(mObserver, PERMISSION_CHANGED_TOPIC, false);
os->AddObserver(mObserver, "screen-information-changed", false);
}
Preferences::AddStrongObserver(mObserver, "intl.accept_languages");
// Watch for storage notifications so we can fire storage events.
RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
if (sns) {
sns->Register(mObserver);
}
if (XRE_IsContentProcess()) {
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
if (docShell) {
mBrowserChild = docShell->GetBrowserChild();
}
}
if (gDumpFile == nullptr) {
nsAutoCString fname;
Preferences::GetCString("browser.dom.window.dump.file", fname);
if (!fname.IsEmpty()) {
// If this fails to open, Dump() knows to just go to stdout on null.
gDumpFile = fopen(fname.get(), "wb+");
} else {
gDumpFile = stdout;
}
}
#ifdef DEBUG
mSerial = nsContentUtils::InnerOrOuterWindowCreated();
MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
static_cast<void*>(ToCanonicalSupports(aOuterWindow))));
#endif
MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
("DOMWINDOW %p created outer=%p", this, aOuterWindow));
// Add ourselves to the inner windows list.
MOZ_ASSERT(sInnerWindowsById, "Inner Windows hash table must be created!");
MOZ_ASSERT(!sInnerWindowsById->Contains(mWindowID),
"This window shouldn't be in the hash table yet!");
// We seem to see crashes in release builds because of null
// |sInnerWindowsById|.
if (sInnerWindowsById) {
sInnerWindowsById->InsertOrUpdate(mWindowID, this);
}
}
#ifdef DEBUG
/* static */
void nsGlobalWindowInner::AssertIsOnMainThread() {
MOZ_ASSERT(NS_IsMainThread());
}
#endif // DEBUG
/* static */
void nsGlobalWindowInner::Init() {
AssertIsOnMainThread();
NS_ASSERTION(gDOMLeakPRLogInner,
"gDOMLeakPRLogInner should have been initialized!");
sInnerWindowsById = new InnerWindowByIdTable();
}
nsGlobalWindowInner::~nsGlobalWindowInner() {
AssertIsOnMainThread();
MOZ_ASSERT(!mHintedWasLoading);
if (IsChromeWindow()) {
MOZ_ASSERT(mCleanMessageManager,
"chrome windows may always disconnect the msg manager");
DisconnectAndClearGroupMessageManagers();
if (mChromeFields.mMessageManager) {
static_cast<nsFrameMessageManager*>(mChromeFields.mMessageManager.get())
->Disconnect();
}
mCleanMessageManager = false;
}
// In most cases this should already have been called, but call it again
// here to catch any corner cases.
FreeInnerObjects();
if (sInnerWindowsById) {
sInnerWindowsById->Remove(mWindowID);
}
nsContentUtils::InnerOrOuterWindowDestroyed();
#ifdef DEBUG
if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)) {
nsAutoCString url;
if (mLastOpenedURI) {
url = mLastOpenedURI->GetSpecOrDefault();
// Data URLs can be very long, so truncate to avoid flooding the log.
const uint32_t maxURLLength = 1000;
if (url.Length() > maxURLLength) {
url.Truncate(maxURLLength);
}
}
nsGlobalWindowOuter* outer = nsGlobalWindowOuter::Cast(mOuterWindow);
MOZ_LOG(
gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n",
nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
static_cast<void*>(ToCanonicalSupports(outer)), url.get()));
}
#endif
MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
("DOMWINDOW %p destroyed", this));
Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
mMutationBits ? 1 : 0);
// An inner window is destroyed, pull it out of the outer window's
// list if inner windows.
PR_REMOVE_LINK(this);
// If our outer window's inner window is this window, null out the
// outer window's reference to this window that's being deleted.
nsGlobalWindowOuter* outer = GetOuterWindowInternal();
if (outer) {
outer->MaybeClearInnerWindow(this);
}
// We don't have to leave the tab group if we are an inner window.
nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
if (ac) ac->RemoveWindowAsListener(this);
nsLayoutStatics::Release();
}
// static
void nsGlobalWindowInner::ShutDown() {
AssertIsOnMainThread();
if (gDumpFile && gDumpFile != stdout) {
fclose(gDumpFile);
}
gDumpFile = nullptr;
delete sInnerWindowsById;
sInnerWindowsById = nullptr;
}
void nsGlobalWindowInner::FreeInnerObjects() {
if (IsDying()) {
return;
}
StartDying();
if (mDoc && mDoc->GetWindowContext()) {
// The document is about to lose its window, so this is a good time to send
// our page use counters.
//
// (We also do this in Document::SetScriptGlobalObject(nullptr), which
// catches most cases of documents losing their window, but not all.)
mDoc->SendPageUseCounters();
}
// Make sure that this is called before we null out the document and
// other members that the window destroyed observers could
// re-create.
NotifyDOMWindowDestroyed(this);
if (auto* reporter = nsWindowMemoryReporter::Get()) {
reporter->ObserveDOMWindowDetached(this);
}
// Kill all of the workers for this window.
CancelWorkersForWindow(*this);
for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
mSharedWorkers.ForwardRange()) {
pinnedWorker->Close();
}
if (mTimeoutManager) {
mTimeoutManager->ClearAllTimeouts();
}
DisableIdleCallbackRequests();
mChromeEventHandler = nullptr;
if (mListenerManager) {
mListenerManager->RemoveAllListeners();
mListenerManager->Disconnect();
mListenerManager = nullptr;
}
mHistory = nullptr;
if (mNavigator) {
mNavigator->OnNavigation();
mNavigator->Invalidate();
mNavigator = nullptr;
}
mScreen = nullptr;
if (mDoc) {
// Remember the document's principal, URI, and CSP.
mDocumentPrincipal = mDoc->NodePrincipal();
mDocumentCookiePrincipal = mDoc->EffectiveCookiePrincipal();
mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
mDocumentPartitionedPrincipal = mDoc->PartitionedPrincipal();
mDocumentURI = mDoc->GetDocumentURI();
mDocBaseURI = mDoc->GetDocBaseURI();
mDocumentCsp = mDoc->GetCsp();
while (mDoc->EventHandlingSuppressed()) {
mDoc->UnsuppressEventHandlingAndFireEvents(false);
}
}
// Remove our reference to the document and the document principal.
mFocusedElement = nullptr;
nsIGlobalObject::UnlinkObjectsInGlobal();
NotifyWindowIDDestroyed("inner-window-destroyed");
for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
mAudioContexts[i]->OnWindowDestroy();
}
mAudioContexts.Clear();
for (MediaKeys* mediaKeys : mMediaKeysInstances) {
mediaKeys->OnInnerWindowDestroy();
}
mMediaKeysInstances.Clear();
DisableGamepadUpdates();
mHasGamepad = false;
mGamepads.Clear();
DisableVRUpdates();
mHasXRSession = false;
mHasVRDisplayActivateEvents = false;
mXRRuntimeDetectionInFlight = false;
mXRPermissionRequestInFlight = false;
mXRPermissionGranted = false;
mVRDisplays.Clear();
// This breaks a cycle between the window and the ClientSource object.
mClientSource.reset();
if (mWindowGlobalChild) {
// Remove any remaining listeners.
int64_t nListeners = mWindowGlobalChild->BeforeUnloadListeners();
for (int64_t i = 0; i < nListeners; ++i) {
mWindowGlobalChild->BeforeUnloadRemoved();
}
MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() == 0);
}
// If we have any promiseDocumentFlushed callbacks, fire them now so
// that the Promises can resolve.
CallDocumentFlushedResolvers(/* aUntilExhaustion = */ true);
DisconnectGlobalTeardownObservers();
#ifdef MOZ_WIDGET_ANDROID
DisableOrientationChangeListener();
#endif
if (mObserver) {
if (nsCOMPtr<nsIObserverService> os = services::GetObserverService()) {
os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
os->RemoveObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC);
os->RemoveObserver(mObserver, PERMISSION_CHANGED_TOPIC);
os->RemoveObserver(mObserver, "screen-information-changed");
}
RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
if (sns) {
sns->Unregister(mObserver);
}
Preferences::RemoveObserver(mObserver, "intl.accept_languages");
// Drop its reference to this dying window, in case for some bogus reason
// the object stays around.
mObserver->Forget();
}
mMenubar = nullptr;
mToolbar = nullptr;
mLocationbar = nullptr;
mPersonalbar = nullptr;
mStatusbar = nullptr;
mScrollbars = nullptr;
mConsole = nullptr;
mPaintWorklet = nullptr;
mExternal = nullptr;
mInstallTrigger = nullptr;
if (mLocalStorage) {
mLocalStorage->Disconnect();
mLocalStorage = nullptr;
}
mSessionStorage = nullptr;
if (mPerformance) {
// Since window is dying, nothing is going to be painted
// with meaningful sizes, so these temp data for LCP is
// no longer needed.
static_cast<PerformanceMainThread*>(mPerformance.get())
->ClearGeneratedTempDataForLCP();
}
mPerformance = nullptr;
mContentMediaController = nullptr;
if (mWebTaskScheduler) {
mWebTaskScheduler->Disconnect();
mWebTaskScheduler = nullptr;
}
mTrustedTypePolicyFactory = nullptr;
mSharedWorkers.Clear();
#ifdef MOZ_WEBSPEECH
mSpeechSynthesis = nullptr;
#endif
mGlean = nullptr;
mGleanPings = nullptr;
mParentTarget = nullptr;
if (mCleanMessageManager) {
MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned");
if (mChromeFields.mMessageManager) {
mChromeFields.mMessageManager->Disconnect();
}
}
if (mWindowGlobalChild && !mWindowGlobalChild->IsClosed()) {
mWindowGlobalChild->Destroy();
}
mIntlUtils = nullptr;
HintIsLoading(false);
}
//*****************************************************************************
// nsGlobalWindowInner::nsISupports
//*****************************************************************************
// QueryInterface implementation for nsGlobalWindowInner
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowInner)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowInner)
NS_INTERFACE_MAP_ENTRY(mozIDOMWindow)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowInner)
if (tmp->IsBlackForCC(false)) {
if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
return true;
}
tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
elm->MarkForCC();
}
if (tmp->mTimeoutManager) {
tmp->mTimeoutManager->UnmarkGrayTimers();
}
return true;
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowInner)
return tmp->IsBlackForCC(true);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowInner)
return tmp->IsBlackForCC(false);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
char name[512];
nsAutoCString uri;
if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
}
SprintfLiteral(name, "nsGlobalWindowInner # %" PRIu64 " inner %s",
tmp->mWindowID, uri.get());
cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
} else {
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowInner, tmp->mRefCnt.get())
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrustedTypePolicyFactory)
#ifdef MOZ_WEBSPEECH
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
#endif
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlean)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGleanPings)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopInnerWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
if (tmp->mTimeoutManager) {
tmp->mTimeoutManager->ForEachUnorderedTimeout([&cb](Timeout* timeout) {
cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout));
});
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorkers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCookiePrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCsp)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
for (IdleRequest* request : tmp->mIdleRequestCallbacks) {
cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClientSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)
// Traverse stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobalChild)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInstallTrigger)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVisualViewport)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPasteDataTransfer)
tmp->TraverseObjectsInGlobal(cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mMessageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mGroupMessageManagers)
for (size_t i = 0; i < tmp->mDocumentFlushedResolvers.Length(); i++) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mPromise);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mCallback);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
if (sInnerWindowsById) {
sInnerWindowsById->Remove(tmp->mWindowID);
}
JSObject* wrapper = tmp->GetWrapperPreserveColor();
if (wrapper) {
// Mark our realm as dead, so the JS engine won't hand out our
// global after this point.
JS::SetRealmNonLive(js::GetNonCCWObjectRealm(wrapper));
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
if (tmp->mWebTaskScheduler) {
tmp->mWebTaskScheduler->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrustedTypePolicyFactory)
#ifdef MOZ_WEBSPEECH
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
#endif
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlean)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGleanPings)
if (tmp->mOuterWindow) {
nsGlobalWindowOuter::Cast(tmp->mOuterWindow)->MaybeClearInnerWindow(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
}
if (tmp->mListenerManager) {
tmp->mListenerManager->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
}
// Here the Timeouts list would've been unlinked, but we rely on
// that Timeout objects have been traced and will remove themselves
// while unlinking.
tmp->UpdateTopInnerWindow();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharedWorkers)
if (tmp->mLocalStorage) {
tmp->mLocalStorage->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCookiePrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCsp)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)
// Unlink stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
MOZ_DIAGNOSTIC_ASSERT(
!tmp->mWindowGlobalChild || tmp->mWindowGlobalChild->IsClosed(),
"How are we unlinking a window before its actor has been destroyed?");
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowGlobalChild)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInstallTrigger)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVisualViewport)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCurrentPasteDataTransfer)
tmp->UnlinkObjectsInGlobal();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)
// Here the IdleRequest list would've been unlinked, but we rely on
// that IdleRequest objects have been traced and will remove
// themselves while unlinking.
NS_IMPL_CYCLE_COLLECTION_UNLINK(mClientSource)