author | Jim Porter <jporter@mozilla.com> |
Tue, 30 Apr 2019 23:31:46 +0000 | |
changeset 472062 | 100acc204e5e0c5e8767740c4861c906e21139f5 |
parent 472061 | a7fa3041bff04a25fa39fb6f714071314f3cc69b |
child 472063 | 9a0ce3016f03a914367e86c8339a8b885e309c83 |
push id | 84445 |
push user | jporter@mozilla.com |
push date | Wed, 01 May 2019 03:29:15 +0000 |
treeherder | autoland@9a0ce3016f03 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug |
bugs | 1493225 |
milestone | 68.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -663,16 +663,26 @@ nsDocShell::GetInterface(const nsIID& aI return nsDocLoader::GetInterface(aIID, aSink); } NS_IF_ADDREF(((nsISupports*)*aSink)); return *aSink ? NS_OK : NS_NOINTERFACE; } NS_IMETHODIMP +nsDocShell::SetCancelContentJSEpoch(int32_t aEpoch) { + // Note: this gets called fairly early (before a pageload actually starts). + // We could probably defer this even longer. + nsCOMPtr<nsIBrowserChild> browserChild = GetBrowserChild(); + static_cast<BrowserChild*>(browserChild.get()) + ->SetCancelContentJSEpoch(aEpoch); + return NS_OK; +} + +NS_IMETHODIMP nsDocShell::LoadURI(nsDocShellLoadState* aLoadState) { MOZ_ASSERT(aLoadState, "Must have a valid load state!"); MOZ_ASSERT( (aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0, "Should not have these flags set"); if (!aLoadState->TriggeringPrincipal()) { #ifndef ANDROID
--- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -70,16 +70,18 @@ native nsDocShellLoadStatePtr(nsDocShell webidl BrowsingContext; webidl ContentFrameMessageManager; webidl EventTarget; webidl Document; [scriptable, builtinclass, uuid(049234fe-da10-478b-bc5d-bc6f9a1ba63d)] interface nsIDocShell : nsIDocShellTreeItem { + void setCancelContentJSEpoch(in long aEpoch); + /** * Loads a given URI. This will give priority to loading the requested URI * in the object implementing this interface. If it can't be loaded here * however, the URL dispatcher will go through its normal process of content * loading. * * @param loadState - This is the extended load info for this load. */
--- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -402,17 +402,18 @@ BrowserChild::BrowserChild(ContentChild* #if defined(ACCESSIBILITY) , mTopLevelDocAccessibleChild(nullptr) #endif , mPendingDocShellIsActive(false), mPendingDocShellReceivedMessage(false), mPendingRenderLayers(false), mPendingRenderLayersReceivedMessage(false), mPendingLayersObserverEpoch{0}, - mPendingDocShellBlockers(0), mWidgetNativeData(0) { + mPendingDocShellBlockers(0), mCancelContentJSEpoch(0), + mWidgetNativeData(0) { mozilla::HoldJSObjects(this); nsWeakPtr weakPtrThis(do_GetWeakReference( static_cast<nsIBrowserChild*>(this))); // for capture by the lambda mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aFlags) { if (nsCOMPtr<nsIBrowserChild> browserChild = @@ -3299,20 +3300,27 @@ void BrowserChild::PaintWhileInterruptin } nsAutoScriptBlocker scriptBlocker; RecvRenderLayers(true /* aEnabled */, aForceRepaint, aEpoch); } nsresult BrowserChild::CanCancelContentJS( nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex, - nsIURI* aNavigationURI, bool* aCanCancel) { + nsIURI* aNavigationURI, int32_t aEpoch, bool* aCanCancel) { nsresult rv; *aCanCancel = false; + if (aEpoch <= mCancelContentJSEpoch) { + // The next page loaded before we got here, so we shouldn't try to cancel + // the content JS. + TABC_LOG("Unable to cancel content JS; the next page is already loaded!\n"); + return NS_OK; + } + nsCOMPtr<nsISHistory> history = do_GetInterface(WebNavigation()); if (!history) { return NS_ERROR_FAILURE; } int32_t current; rv = history->GetIndex(¤t); NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/ipc/BrowserChild.h +++ b/dom/ipc/BrowserChild.h @@ -609,17 +609,17 @@ class BrowserChild final : public Browse const CSSRect& aRect, const uint32_t& aFlags); // Request that the docshell be marked as active. void PaintWhileInterruptingJS(const layers::LayersObserverEpoch& aEpoch, bool aForceRepaint); nsresult CanCancelContentJS(nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex, nsIURI* aNavigationURI, - bool* aCanCancel); + int32_t aEpoch, bool* aCanCancel); layers::LayersObserverEpoch LayersObserverEpoch() const { return mLayersObserverEpoch; } #if defined(XP_WIN) && defined(ACCESSIBILITY) uintptr_t GetNativeWindowHandle() const { return mNativeWindowHandle; } #endif @@ -659,16 +659,20 @@ class BrowserChild final : public Browse // dispatching some mouse events other than mousemove. void FlushAllCoalescedMouseData(); void ProcessPendingCoalescedMouseDataAndDispatchEvents(); void HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId); + void SetCancelContentJSEpoch(int32_t aEpoch) { + mCancelContentJSEpoch = aEpoch; + } + static bool HasVisibleTabs() { return sVisibleTabs && !sVisibleTabs->IsEmpty(); } // Returns the set of BrowserChilds that are currently rendering layers. There // can be multiple BrowserChilds in this state if Firefox has multiple windows // open or is warming tabs up. There can also be zero BrowserChilds in this // state. Note that this function should only be called if HasVisibleTabs() @@ -915,16 +919,17 @@ class BrowserChild final : public Browse bool mPendingDocShellIsActive; bool mPendingDocShellReceivedMessage; bool mPendingRenderLayers; bool mPendingRenderLayersReceivedMessage; layers::LayersObserverEpoch mPendingLayersObserverEpoch; // When mPendingDocShellBlockers is greater than 0, the DocShell is blocked, // and once it reaches 0, it is no longer blocked. uint32_t mPendingDocShellBlockers; + int32_t mCancelContentJSEpoch; WindowsHandle mWidgetNativeData; Maybe<LayoutDeviceToLayoutDeviceMatrix4x4> mChildToParentConversionMatrix; // This state is used to keep track of the current visible tabs (the ones // rendering layers). There may be more than one if there are multiple browser // windows open, or tabs are being warmed up. There may be none if this
--- a/dom/ipc/PProcessHangMonitor.ipdl +++ b/dom/ipc/PProcessHangMonitor.ipdl @@ -45,12 +45,12 @@ child: async BeginStartingDebugger(); async EndStartingDebugger(); async PaintWhileInterruptingJS(TabId tabId, bool forceRepaint, LayersObserverEpoch aEpoch); async CancelContentJSExecutionIfRunning( TabId tabId, NavigationType aNavigationType, - int32_t aNavigationIndex, nsCString? aNavigationURI); + int32_t aNavigationIndex, nsCString? aNavigationURI, int32_t aEpoch); }; } // namespace mozilla
--- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -113,17 +113,18 @@ class HangMonitorChild : public PProcess mozilla::ipc::IPCResult RecvPaintWhileInterruptingJS( const TabId& aTabId, const bool& aForceRepaint, const LayersObserverEpoch& aEpoch) override; mozilla::ipc::IPCResult RecvCancelContentJSExecutionIfRunning( const TabId& aTabId, const nsIRemoteTab::NavigationType& aNavigationType, const int32_t& aNavigationIndex, - const mozilla::Maybe<nsCString>& aNavigationURI) override; + const mozilla::Maybe<nsCString>& aNavigationURI, + const int32_t& aEpoch) override; void ActorDestroy(ActorDestroyReason aWhy) override; void InterruptCallback(); void Shutdown(); static HangMonitorChild* Get() { return sInstance; } @@ -158,16 +159,17 @@ class HangMonitorChild : public PProcess bool mPaintWhileInterruptingJSForce; TabId mPaintWhileInterruptingJSTab; MOZ_INIT_OUTSIDE_CTOR LayersObserverEpoch mPaintWhileInterruptingJSEpoch; bool mCancelContentJS; TabId mCancelContentJSTab; nsIRemoteTab::NavigationType mCancelContentJSNavigationType; int32_t mCancelContentJSNavigationIndex; mozilla::Maybe<nsCString> mCancelContentJSNavigationURI; + int32_t mCancelContentJSEpoch; JSContext* mContext; bool mShutdownDone; // This field is only accessed on the hang thread. bool mIPCOpen; // Allows us to ensure we NotifyActivity only once, allowing // either thread to do so. @@ -276,17 +278,17 @@ class HangMonitorParent : public PProces const nsString& aBrowserDumpId, bool aTakeMinidump); void ClearHangNotification(); void PaintWhileInterruptingJSOnThread(TabId aTabId, bool aForceRepaint, const LayersObserverEpoch& aEpoch); void CancelContentJSExecutionIfRunningOnThread( TabId aTabId, nsIRemoteTab::NavigationType aNavigationType, - int32_t aNavigationIndex, nsIURI* aNavigationURI); + int32_t aNavigationIndex, nsIURI* aNavigationURI, int32_t aEpoch); void ShutdownOnThread(); const RefPtr<ProcessHangMonitor> mHangMonitor; // This field is read-only after construction. bool mReportHangs; @@ -323,16 +325,17 @@ HangMonitorChild::HangMonitorChild(Proce mTerminateGlobal(false), mStartDebugger(false), mFinishedStartingDebugger(false), mPaintWhileInterruptingJS(false), mPaintWhileInterruptingJSForce(false), mCancelContentJS(false), mCancelContentJSNavigationType(nsIRemoteTab::NAVIGATE_BACK), mCancelContentJSNavigationIndex(0), + mCancelContentJSEpoch(0), mShutdownDone(false), mIPCOpen(true), mPaintWhileInterruptingJSActive(false) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); mContext = danger::GetJSContext(); BackgroundHangMonitor::RegisterAnnotator(*this); } @@ -351,29 +354,31 @@ void HangMonitorChild::InterruptCallback TabId paintWhileInterruptingJSTab; LayersObserverEpoch paintWhileInterruptingJSEpoch; bool cancelContentJS; TabId cancelContentJSTab; nsIRemoteTab::NavigationType cancelContentJSNavigationType; int32_t cancelContentJSNavigationIndex; mozilla::Maybe<nsCString> cancelContentJSNavigationURI; + int32_t cancelContentJSEpoch; { MonitorAutoLock lock(mMonitor); paintWhileInterruptingJS = mPaintWhileInterruptingJS; paintWhileInterruptingJSForce = mPaintWhileInterruptingJSForce; paintWhileInterruptingJSTab = mPaintWhileInterruptingJSTab; paintWhileInterruptingJSEpoch = mPaintWhileInterruptingJSEpoch; cancelContentJS = mCancelContentJS; cancelContentJSTab = mCancelContentJSTab; cancelContentJSNavigationType = mCancelContentJSNavigationType; cancelContentJSNavigationIndex = mCancelContentJSNavigationIndex; cancelContentJSNavigationURI = std::move(mCancelContentJSNavigationURI); + cancelContentJSEpoch = mCancelContentJSEpoch; mPaintWhileInterruptingJS = false; mCancelContentJS = false; } // Don't paint from the interrupt callback when recording or replaying, as // the interrupt callback is triggered non-deterministically. if (paintWhileInterruptingJS && !recordreplay::IsRecordingOrReplaying()) { @@ -400,17 +405,17 @@ void HangMonitorChild::InterruptCallback if (NS_FAILED(rv)) { return; } } bool canCancel; rv = browserChild->CanCancelContentJS(cancelContentJSNavigationType, cancelContentJSNavigationIndex, uri, - &canCancel); + cancelContentJSEpoch, &canCancel); if (NS_SUCCEEDED(rv) && canCancel) { // Tell xpconnect that we want to cancel the content JS in this tab // during the next interrupt callback. XPCJSContext::SetTabIdToCancelContentJS(cancelContentJSTab); JS_RequestInterruptCallback(mContext); } } } @@ -511,26 +516,27 @@ void HangMonitorChild::ClearPaintWhileIn MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(XRE_IsContentProcess()); mPaintWhileInterruptingJSActive = false; } mozilla::ipc::IPCResult HangMonitorChild::RecvCancelContentJSExecutionIfRunning( const TabId& aTabId, const nsIRemoteTab::NavigationType& aNavigationType, const int32_t& aNavigationIndex, - const mozilla::Maybe<nsCString>& aNavigationURI) { + const mozilla::Maybe<nsCString>& aNavigationURI, const int32_t& aEpoch) { MOZ_RELEASE_ASSERT(IsOnThread()); { MonitorAutoLock lock(mMonitor); mCancelContentJS = true; mCancelContentJSTab = aTabId; mCancelContentJSNavigationType = aNavigationType; mCancelContentJSNavigationIndex = aNavigationIndex; mCancelContentJSNavigationURI = aNavigationURI; + mCancelContentJSEpoch = aEpoch; } JS_RequestInterruptCallback(mContext); return IPC_OK(); } void HangMonitorChild::Bind(Endpoint<PProcessHangMonitorChild>&& aEndpoint) { @@ -744,40 +750,40 @@ void HangMonitorParent::PaintWhileInterr void HangMonitorParent::CancelContentJSExecutionIfRunning( dom::BrowserParent* aBrowserParent, nsIRemoteTab::NavigationType aNavigationType, const dom::CancelContentJSOptions& aCancelContentJSOptions) { MOZ_RELEASE_ASSERT(NS_IsMainThread()); TabId id = aBrowserParent->GetTabId(); Dispatch(NewNonOwningRunnableMethod<TabId, nsIRemoteTab::NavigationType, - int32_t, nsIURI*>( + int32_t, nsIURI*, int32_t>( "HangMonitorParent::CancelContentJSExecutionIfRunningOnThread", this, &HangMonitorParent::CancelContentJSExecutionIfRunningOnThread, id, aNavigationType, aCancelContentJSOptions.mIndex, - aCancelContentJSOptions.mUri)); + aCancelContentJSOptions.mUri, aCancelContentJSOptions.mEpoch)); } void HangMonitorParent::CancelContentJSExecutionIfRunningOnThread( TabId aTabId, nsIRemoteTab::NavigationType aNavigationType, - int32_t aNavigationIndex, nsIURI* aNavigationURI) { + int32_t aNavigationIndex, nsIURI* aNavigationURI, int32_t aEpoch) { MOZ_RELEASE_ASSERT(IsOnThread()); mozilla::Maybe<nsCString> spec; if (aNavigationURI) { nsAutoCString tmp; nsresult rv = aNavigationURI->GetSpec(tmp); if (NS_SUCCEEDED(rv)) { spec.emplace(tmp); } } if (mIPCOpen) { - Unused << SendCancelContentJSExecutionIfRunning(aTabId, aNavigationType, - aNavigationIndex, spec); + Unused << SendCancelContentJSExecutionIfRunning( + aTabId, aNavigationType, aNavigationIndex, spec, aEpoch); } } void HangMonitorParent::ActorDestroy(ActorDestroyReason aWhy) { MOZ_RELEASE_ASSERT(IsOnThread()); mIPCOpen = false; }
--- a/dom/webidl/CancelContentJSOptions.webidl +++ b/dom/webidl/CancelContentJSOptions.webidl @@ -1,8 +1,9 @@ /* 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/. */ dictionary CancelContentJSOptions { long index = 0; URI? uri = null; + long epoch = 0; };
--- a/toolkit/actors/WebNavigationChild.jsm +++ b/toolkit/actors/WebNavigationChild.jsm @@ -22,23 +22,23 @@ XPCOMUtils.defineLazyServiceGetter(this, class WebNavigationChild extends ActorChild { get webNavigation() { return this.mm.docShell.QueryInterface(Ci.nsIWebNavigation); } receiveMessage(message) { switch (message.name) { case "WebNavigation:GoBack": - this.goBack(); + this.goBack(message.data); break; case "WebNavigation:GoForward": - this.goForward(); + this.goForward(message.data); break; case "WebNavigation:GotoIndex": - this.gotoIndex(message.data.index); + this.gotoIndex(message.data); break; case "WebNavigation:LoadURI": let histogram = Services.telemetry.getKeyedHistogramById("FX_TAB_REMOTE_NAVIGATION_DELAY_MS"); histogram.add("WebNavigation:LoadURI", Services.telemetry.msSystemNow() - message.data.requestTime); this.loadURI(message.data); @@ -60,42 +60,50 @@ class WebNavigationChild extends ActorCh try { fn(); } finally { this.mm.WebProgress.inLoadURI = false; this.mm.WebProgress.sendLoadCallResult(); } } - goBack() { + goBack(params) { if (this.webNavigation.canGoBack) { + this.mm.docShell.setCancelContentJSEpoch(params.cancelContentJSEpoch); this._wrapURIChangeCall(() => this.webNavigation.goBack()); } } - goForward() { + goForward(params) { if (this.webNavigation.canGoForward) { + this.mm.docShell.setCancelContentJSEpoch(params.cancelContentJSEpoch); this._wrapURIChangeCall(() => this.webNavigation.goForward()); } } - gotoIndex(index) { + gotoIndex(params) { + let { + index, + cancelContentJSEpoch, + } = params || {}; + this.mm.docShell.setCancelContentJSEpoch(cancelContentJSEpoch); this._wrapURIChangeCall(() => this.webNavigation.gotoIndex(index)); } loadURI(params) { let { uri, flags, referrerInfo, postData, headers, baseURI, triggeringPrincipal, csp, + cancelContentJSEpoch, } = params || {}; if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) { let annotation = uri; try { let url = Services.io.newURI(uri); // If the current URI contains a username/password, remove it. url = url.mutate() @@ -126,16 +134,17 @@ class WebNavigationChild extends ActorCh triggeringPrincipal, csp, loadFlags: flags, referrerInfo: E10SUtils.deserializeReferrerInfo(referrerInfo), postData, headers, baseURI, }; + this.mm.docShell.setCancelContentJSEpoch(cancelContentJSEpoch); this._wrapURIChangeCall(() => { return this.webNavigation.loadURI(uri, loadURIOptions); }); } _assert(condition, msg, line = 0) { let debug = Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2); if (!condition && debug.isDebugBuild) {
--- a/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm +++ b/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm @@ -13,16 +13,17 @@ ChromeUtils.defineModuleGetter(this, "E1 "resource://gre/modules/E10SUtils.jsm"); function makeURI(url) { return Services.io.newURI(url); } function RemoteWebNavigation() { this.wrappedJSObject = this; + this._cancelContentJSEpoch = 1; } RemoteWebNavigation.prototype = { classDescription: "nsIWebNavigation for remote browsers", classID: Components.ID("{4b56964e-cdf3-4bb8-830c-0e2dad3f4ebd}"), contractID: "@mozilla.org/remote-web-navigation;1", QueryInterface: ChromeUtils.generateQI([Ci.nsIWebNavigation]), @@ -50,29 +51,34 @@ RemoteWebNavigation.prototype = { STOP_NETWORK: 1, STOP_CONTENT: 2, STOP_ALL: 3, canGoBack: false, canGoForward: false, goBack() { + let cancelContentJSEpoch = this._cancelContentJSEpoch++; this._browser.frameLoader.remoteTab.maybeCancelContentJSExecution( - Ci.nsIRemoteTab.NAVIGATE_BACK); - this._sendMessage("WebNavigation:GoBack", {}); + Ci.nsIRemoteTab.NAVIGATE_BACK, {epoch: cancelContentJSEpoch}); + this._sendMessage("WebNavigation:GoBack", {cancelContentJSEpoch}); }, goForward() { + let cancelContentJSEpoch = this._cancelContentJSEpoch++; this._browser.frameLoader.remoteTab.maybeCancelContentJSExecution( - Ci.nsIRemoteTab.NAVIGATE_FORWARD); - this._sendMessage("WebNavigation:GoForward", {}); + Ci.nsIRemoteTab.NAVIGATE_FORWARD, {epoch: cancelContentJSEpoch}); + this._sendMessage("WebNavigation:GoForward", {cancelContentJSEpoch}); }, gotoIndex(aIndex) { + let cancelContentJSEpoch = this._cancelContentJSEpoch++; this._browser.frameLoader.remoteTab.maybeCancelContentJSExecution( - Ci.nsIRemoteTab.NAVIGATE_INDEX, {index: aIndex}); - this._sendMessage("WebNavigation:GotoIndex", {index: aIndex}); + Ci.nsIRemoteTab.NAVIGATE_INDEX, + {index: aIndex, epoch: cancelContentJSEpoch}); + this._sendMessage("WebNavigation:GotoIndex", {index: aIndex, + cancelContentJSEpoch}); }, loadURI(aURI, aLoadURIOptions) { let uri; // We know the url is going to be loaded, let's start requesting network // connection before the content process asks. // Note that we might have already setup the speculative connection in some // cases, especially when the url is from location bar or its popup menu. @@ -92,29 +98,31 @@ RemoteWebNavigation.prototype = { } Services.io.speculativeConnect(uri, principal, null); } catch (ex) { // Can't setup speculative connection for this uri string for some // reason (such as failing to parse the URI), just ignore it. } } + let cancelContentJSEpoch = this._cancelContentJSEpoch++; this._browser.frameLoader.remoteTab.maybeCancelContentJSExecution( - Ci.nsIRemoteTab.NAVIGATE_URL, {uri}); + Ci.nsIRemoteTab.NAVIGATE_URL, {uri, epoch: cancelContentJSEpoch}); this._sendMessage("WebNavigation:LoadURI", { uri: aURI, flags: aLoadURIOptions.loadFlags, referrerInfo: E10SUtils.serializeReferrerInfo(aLoadURIOptions.referrerInfo), postData: aLoadURIOptions.postData ? Utils.serializeInputStream(aLoadURIOptions.postData) : null, headers: aLoadURIOptions.headers ? Utils.serializeInputStream(aLoadURIOptions.headers) : null, baseURI: aLoadURIOptions.baseURI ? aLoadURIOptions.baseURI.spec : null, triggeringPrincipal: E10SUtils.serializePrincipal( aLoadURIOptions.triggeringPrincipal || Services.scriptSecurityManager.createNullPrincipal({})), csp: aLoadURIOptions.csp ? E10SUtils.serializeCSP(aLoadURIOptions.csp) : null, requestTime: Services.telemetry.msSystemNow(), + cancelContentJSEpoch, }); }, setOriginAttributesBeforeLoading(aOriginAttributes) { this._sendMessage("WebNavigation:SetOriginAttributes", { originAttributes: aOriginAttributes, }); }, reload(aReloadFlags) {