Bug 1598775 - Ensure postMessage related optimizations during page load work also in Fission, r=farre

Bug 1534012 added a test for postMessage during load and that revealed that mLoading flag isn't always updated
soon enough, so add BrowsingContext::IsLoading which checks also possible local loading status.

Depends on D54754

Differential Revision: https://phabricator.services.mozilla.com/D54836

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Olli Pettay 2019-11-30 21:13:54 +00:00
Родитель e2d1797ad5
Коммит 7f0bc5d8d8
10 изменённых файлов: 100 добавлений и 81 удалений

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/dom/BrowsingContextBinding.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Location.h"
#include "mozilla/dom/LocationBinding.h"
@ -1349,17 +1350,40 @@ void BrowsingContext::DidSetIsPopupSpam() {
}
}
bool BrowsingContext::IsLoading() {
if (GetLoading()) {
return true;
}
// If we're in the same process as the page, we're possibly just
// updating the flag.
nsIDocShell* shell = GetDocShell();
if (shell) {
Document* doc = shell->GetDocument();
return doc && doc->GetReadyStateEnum() < Document::READYSTATE_COMPLETE;
}
return false;
}
void BrowsingContext::DidSetLoading() {
if (!mLoading) {
while (!mDeprioritizedLoadRunner.isEmpty()) {
nsCOMPtr<nsIRunnable> runner = mDeprioritizedLoadRunner.popFirst();
NS_DispatchToCurrentThread(runner.forget());
}
if (mLoading) {
return;
}
while (!mDeprioritizedLoadRunner.isEmpty()) {
nsCOMPtr<nsIRunnable> runner = mDeprioritizedLoadRunner.popFirst();
NS_DispatchToCurrentThread(runner.forget());
}
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled() &&
Top() == this) {
Group()->FlushPostMessageEvents();
}
}
void BrowsingContext::AddDeprioritizedLoadRunner(nsIRunnable* aRunner) {
MOZ_ASSERT(mLoading);
MOZ_ASSERT(IsLoading());
MOZ_ASSERT(Top() == this);
RefPtr<DeprioritizedLoadRunner> runner = new DeprioritizedLoadRunner(aRunner);

Просмотреть файл

@ -272,6 +272,8 @@ class BrowsingContext : public nsISupports,
bool InRDMPane() { return mInRDMPane; }
bool IsLoading();
// Using the rules for choosing a browsing context we try to find
// the browsing context with the given name in the set of
// transitively reachable browsing contexts. Performs access control

Просмотреть файл

@ -7,6 +7,8 @@
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/BrowsingContextBinding.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/ThrottledEventQueue.h"
namespace mozilla {
namespace dom {
@ -133,6 +135,46 @@ JSObject* BrowsingContextGroup::WrapObject(JSContext* aCx,
return BrowsingContextGroup_Binding::Wrap(aCx, this, aGivenProto);
}
nsresult BrowsingContextGroup::QueuePostMessageEvent(
already_AddRefed<nsIRunnable>&& aRunnable) {
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled()) {
if (!mPostMessageEventQueue) {
nsCOMPtr<nsISerialEventTarget> target = GetMainThreadSerialEventTarget();
mPostMessageEventQueue = ThrottledEventQueue::Create(
target, "PostMessage Queue",
nsIRunnablePriority::PRIORITY_DEFERRED_TIMERS);
nsresult rv = mPostMessageEventQueue->SetIsPaused(false);
MOZ_ALWAYS_SUCCEEDS(rv);
}
// Ensure the queue is enabled
if (mPostMessageEventQueue->IsPaused()) {
nsresult rv = mPostMessageEventQueue->SetIsPaused(false);
MOZ_ALWAYS_SUCCEEDS(rv);
}
if (mPostMessageEventQueue) {
mPostMessageEventQueue->Dispatch(std::move(aRunnable),
NS_DISPATCH_NORMAL);
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
void BrowsingContextGroup::FlushPostMessageEvents() {
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled()) {
if (mPostMessageEventQueue) {
nsresult rv = mPostMessageEventQueue->SetIsPaused(true);
MOZ_ALWAYS_SUCCEEDS(rv);
nsCOMPtr<nsIRunnable> event;
while ((event = mPostMessageEventQueue->GetEvent())) {
NS_DispatchToMainThread(event.forget());
}
}
}
}
static StaticRefPtr<BrowsingContextGroup> sChromeGroup;
/* static */

Просмотреть файл

@ -15,6 +15,8 @@
#include "nsWrapperCache.h"
namespace mozilla {
class ThrottledEventQueue;
namespace dom {
class BrowsingContext;
@ -108,6 +110,10 @@ class BrowsingContextGroup final : public nsWrapperCache {
}
}
nsresult QueuePostMessageEvent(already_AddRefed<nsIRunnable>&& aRunnable);
void FlushPostMessageEvents();
static BrowsingContextGroup* GetChromeGroup();
private:
@ -129,6 +135,10 @@ class BrowsingContextGroup final : public nsWrapperCache {
// Map of cached contexts that need to stay alive due to bfcache.
nsTHashtable<nsRefPtrHashKey<BrowsingContext>> mCachedContexts;
// A queue to store postMessage events during page load, the queue will be
// flushed once the page is loaded
RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;
};
} // namespace dom

Просмотреть файл

@ -255,46 +255,6 @@ bool TabGroup::IsBackground() const {
return mForegroundCount == 0;
}
nsresult TabGroup::QueuePostMessageEvent(
already_AddRefed<nsIRunnable>&& aRunnable) {
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled()) {
if (!mPostMessageEventQueue) {
nsCOMPtr<nsISerialEventTarget> target = GetMainThreadSerialEventTarget();
mPostMessageEventQueue = ThrottledEventQueue::Create(
target, "PostMessage Queue",
nsIRunnablePriority::PRIORITY_DEFERRED_TIMERS);
nsresult rv = mPostMessageEventQueue->SetIsPaused(false);
MOZ_ALWAYS_SUCCEEDS(rv);
}
// Ensure the queue is enabled
if (mPostMessageEventQueue->IsPaused()) {
nsresult rv = mPostMessageEventQueue->SetIsPaused(false);
MOZ_ALWAYS_SUCCEEDS(rv);
}
if (mPostMessageEventQueue) {
mPostMessageEventQueue->Dispatch(std::move(aRunnable),
NS_DISPATCH_NORMAL);
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
void TabGroup::FlushPostMessageEvents() {
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled()) {
if (mPostMessageEventQueue) {
nsresult rv = mPostMessageEventQueue->SetIsPaused(true);
MOZ_ALWAYS_SUCCEEDS(rv);
nsCOMPtr<nsIRunnable> event;
while ((event = mPostMessageEventQueue->GetEvent())) {
Dispatch(TaskCategory::Other, event.forget());
}
}
}
}
uint32_t TabGroup::Count(bool aActiveOnly) const {
if (!aActiveOnly) {
return mDocGroups.Count();

Просмотреть файл

@ -130,10 +130,6 @@ class TabGroup final : public SchedulerGroup,
// can be throttled.
static bool HasOnlyThrottableTabs();
nsresult QueuePostMessageEvent(already_AddRefed<nsIRunnable>&& aRunnable);
void FlushPostMessageEvents();
private:
virtual AbstractThread* AbstractMainThreadForImpl(
TaskCategory aCategory) override;
@ -157,10 +153,6 @@ class TabGroup final : public SchedulerGroup,
uint32_t mForegroundCount;
static LinkedList<TabGroup>* sTabGroups;
// A queue to store postMessage events during page load, the queue will be
// flushed once the page is loaded
RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;
};
} // namespace dom

Просмотреть файл

@ -2564,18 +2564,6 @@ void nsGlobalWindowInner::SetActiveLoadingState(bool aIsLoading) {
GetBrowsingContext()->SetLoading(aIsLoading);
}
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled()) {
if (!aIsLoading) {
Document* doc = GetExtantDoc();
if (doc) {
if (doc->IsTopLevelContentDocument()) {
mozilla::dom::TabGroup* tabGroup = doc->GetDocGroup()->GetTabGroup();
tabGroup->FlushPostMessageEvents();
}
}
}
}
if (!nsGlobalWindowInner::Cast(this)->IsChromeWindow()) {
mTimeoutManager->SetLoading(aIsLoading);
}

Просмотреть файл

@ -219,6 +219,7 @@
#include "nsXULControllers.h"
#include "mozilla/dom/AudioContext.h"
#include "mozilla/dom/BrowserElementDictionariesBinding.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/cache/CacheStorage.h"
#include "mozilla/dom/Console.h"
#include "mozilla/dom/Fetch.h"
@ -6076,33 +6077,33 @@ void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
return;
}
if (mDoc &&
StaticPrefs::dom_separate_event_queue_for_post_message_enabled() &&
if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled() &&
!DocGroup::TryToLoadIframesInBackground()) {
Document* doc = mDoc->GetTopLevelContentDocument();
if (doc && doc->GetReadyStateEnum() < Document::READYSTATE_COMPLETE) {
BrowsingContext* bc = GetBrowsingContext();
bc = bc ? bc->Top() : nullptr;
if (bc && bc->IsLoading()) {
// As long as the top level is loading, we can dispatch events to the
// queue because the queue will be flushed eventually
mozilla::dom::TabGroup* tabGroup = TabGroup();
aError = tabGroup->QueuePostMessageEvent(event.forget());
aError = bc->Group()->QueuePostMessageEvent(event.forget());
return;
}
}
if (mDoc && DocGroup::TryToLoadIframesInBackground()) {
if (DocGroup::TryToLoadIframesInBackground()) {
RefPtr<nsIDocShell> docShell = GetDocShell();
RefPtr<nsDocShell> dShell = nsDocShell::Cast(docShell);
// PostMessage that are added to the tabGroup are the ones that
// can be flushed when the top level document is loaded
// PostMessage that are added to the BrowsingContextGroup are the ones that
// can be flushed when the top level document is loaded.
// TreadAsBackgroundLoad DocShells are treated specially.
if (dShell) {
if (!dShell->TreatAsBackgroundLoad()) {
Document* doc = mDoc->GetTopLevelContentDocument();
if (doc && doc->GetReadyStateEnum() < Document::READYSTATE_COMPLETE) {
BrowsingContext* bc = GetBrowsingContext();
bc = bc ? bc->Top() : nullptr;
if (bc && bc->IsLoading()) {
// As long as the top level is loading, we can dispatch events to the
// queue because the queue will be flushed eventually
mozilla::dom::TabGroup* tabGroup = TabGroup();
aError = tabGroup->QueuePostMessageEvent(event.forget());
aError = bc->Group()->QueuePostMessageEvent(event.forget());
return;
}
} else if (mDoc->GetReadyStateEnum() < Document::READYSTATE_COMPLETE) {

Просмотреть файл

@ -585,7 +585,7 @@ void MainThreadFetchResolver::OnResponseAvailableInternal(
nsCOMPtr<nsPIDOMWindowInner> inner = do_QueryInterface(go);
BrowsingContext* bc = inner ? inner->GetBrowsingContext() : nullptr;
bc = bc ? bc->Top() : nullptr;
if (bc && bc->GetLoading()) {
if (bc && bc->IsLoading()) {
bc->AddDeprioritizedLoadRunner(
new ResolveFetchPromise(mPromise, mResponse));
} else {

Просмотреть файл

@ -2310,7 +2310,7 @@ void XMLHttpRequestMainThread::ChangeStateToDone(bool aWasSync) {
nsPIDOMWindowInner* owner = GetOwner();
BrowsingContext* bc = owner ? owner->GetBrowsingContext() : nullptr;
bc = bc ? bc->Top() : nullptr;
if (bc && bc->GetLoading()) {
if (bc && bc->IsLoading()) {
MOZ_ASSERT(!mDelayedDoneNotifier);
RefPtr<XMLHttpRequestDoneNotifier> notifier =
new XMLHttpRequestDoneNotifier(this);