mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Backed out 7 changesets (bug 1193394) for browser-chrome failures on browser_ext_popup_background.js. CLOSED TREE
Backed out changeset 9683f24ff8ec (bug 1193394) Backed out changeset 0e7140a7c841 (bug 1193394) Backed out changeset a0e26f6b2784 (bug 1193394) Backed out changeset 29e1fceaf48d (bug 1193394) Backed out changeset b8632bbbd273 (bug 1193394) Backed out changeset a54ef2d8f896 (bug 1193394) Backed out changeset 55c94c05c57f (bug 1193394)
This commit is contained in:
parent
e497c77767
commit
1fd0486e23
@ -5,7 +5,6 @@ support-files=
|
|||||||
|
|
||||||
[browser_canvas_fingerprinting_resistance.js]
|
[browser_canvas_fingerprinting_resistance.js]
|
||||||
[browser_permissions.js]
|
[browser_permissions.js]
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_reservedkey.js]
|
[browser_reservedkey.js]
|
||||||
[browser_temporary_permissions.js]
|
[browser_temporary_permissions.js]
|
||||||
support-files =
|
support-files =
|
||||||
|
@ -102,5 +102,3 @@ tags = mcb
|
|||||||
support-files =
|
support-files =
|
||||||
test_no_mcb_for_onions.html
|
test_no_mcb_for_onions.html
|
||||||
[browser_check_identity_state.js]
|
[browser_check_identity_state.js]
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
|
|
||||||
|
@ -6,20 +6,16 @@ support-files =
|
|||||||
head.js
|
head.js
|
||||||
|
|
||||||
[browser_devices_get_user_media.js]
|
[browser_devices_get_user_media.js]
|
||||||
#skip-if = (os == "linux" && debug) # linux: bug 976544
|
skip-if = (os == "linux" && debug) # linux: bug 976544
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_devices_get_user_media_anim.js]
|
[browser_devices_get_user_media_anim.js]
|
||||||
[browser_devices_get_user_media_in_frame.js]
|
[browser_devices_get_user_media_in_frame.js]
|
||||||
#skip-if = debug # bug 1369731
|
skip-if = debug # bug 1369731
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_devices_get_user_media_multi_process.js]
|
[browser_devices_get_user_media_multi_process.js]
|
||||||
skip-if = debug && (os == "win" || os == "mac") # bug 1393761
|
skip-if = debug && (os == "win" || os == "mac") # bug 1393761
|
||||||
[browser_devices_get_user_media_paused.js]
|
[browser_devices_get_user_media_paused.js]
|
||||||
[browser_devices_get_user_media_screen.js]
|
[browser_devices_get_user_media_screen.js]
|
||||||
#skip-if = (os == "win" && ccov) # bug 1421724
|
skip-if = (os == "win" && ccov) # bug 1421724
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_devices_get_user_media_tear_off_tab.js]
|
[browser_devices_get_user_media_tear_off_tab.js]
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_devices_get_user_media_unprompted_access.js]
|
[browser_devices_get_user_media_unprompted_access.js]
|
||||||
[browser_devices_get_user_media_unprompted_access_in_frame.js]
|
[browser_devices_get_user_media_unprompted_access_in_frame.js]
|
||||||
[browser_devices_get_user_media_unprompted_access_tear_off_tab.js]
|
[browser_devices_get_user_media_unprompted_access_tear_off_tab.js]
|
||||||
|
@ -155,7 +155,6 @@ tags = fullscreen
|
|||||||
[browser_remove_customized_specials.js]
|
[browser_remove_customized_specials.js]
|
||||||
[browser_switch_to_customize_mode.js]
|
[browser_switch_to_customize_mode.js]
|
||||||
[browser_synced_tabs_menu.js]
|
[browser_synced_tabs_menu.js]
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_backfwd_enabled_post_customize.js]
|
[browser_backfwd_enabled_post_customize.js]
|
||||||
[browser_check_tooltips_in_navbar.js]
|
[browser_check_tooltips_in_navbar.js]
|
||||||
[browser_editcontrols_update.js]
|
[browser_editcontrols_update.js]
|
||||||
|
@ -48,12 +48,10 @@ skip-if = os == 'linux'
|
|||||||
[browser_ext_browserAction_pageAction_icon.js]
|
[browser_ext_browserAction_pageAction_icon.js]
|
||||||
[browser_ext_browserAction_pageAction_icon_permissions.js]
|
[browser_ext_browserAction_pageAction_icon_permissions.js]
|
||||||
[browser_ext_browserAction_popup.js]
|
[browser_ext_browserAction_popup.js]
|
||||||
#skip-if = (debug && os == 'linux' && bits == 32) || (os == 'win' && !debug) # Bug 1313372, win: Bug 1285500
|
skip-if = (debug && os == 'linux' && bits == 32) || (os == 'win' && !debug) # Bug 1313372, win: Bug 1285500
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_ext_browserAction_popup_preload.js]
|
[browser_ext_browserAction_popup_preload.js]
|
||||||
skip-if = (os == 'win' && !debug) # bug 1352668
|
skip-if = (os == 'win' && !debug) # bug 1352668
|
||||||
[browser_ext_browserAction_popup_resize.js]
|
[browser_ext_browserAction_popup_resize.js]
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_ext_browserAction_simple.js]
|
[browser_ext_browserAction_simple.js]
|
||||||
[browser_ext_browserAction_telemetry.js]
|
[browser_ext_browserAction_telemetry.js]
|
||||||
[browser_ext_browserAction_theme_icons.js]
|
[browser_ext_browserAction_theme_icons.js]
|
||||||
@ -65,7 +63,6 @@ skip-if = true # temporarily disabled for bug 1193394
|
|||||||
[browser_ext_browsingData_serviceWorkers.js]
|
[browser_ext_browsingData_serviceWorkers.js]
|
||||||
[browser_ext_chrome_settings_overrides_home.js]
|
[browser_ext_chrome_settings_overrides_home.js]
|
||||||
[browser_ext_commands_execute_browser_action.js]
|
[browser_ext_commands_execute_browser_action.js]
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_ext_commands_execute_page_action.js]
|
[browser_ext_commands_execute_page_action.js]
|
||||||
[browser_ext_commands_execute_sidebar_action.js]
|
[browser_ext_commands_execute_sidebar_action.js]
|
||||||
[browser_ext_commands_getAll.js]
|
[browser_ext_commands_getAll.js]
|
||||||
|
@ -12,8 +12,7 @@ skip-if = !e10s # Bug 1373549
|
|||||||
[browser_BrowserUITelemetry_sidebar.js]
|
[browser_BrowserUITelemetry_sidebar.js]
|
||||||
skip-if = !e10s # Bug 1373549
|
skip-if = !e10s # Bug 1373549
|
||||||
[browser_BrowserUITelemetry_syncedtabs.js]
|
[browser_BrowserUITelemetry_syncedtabs.js]
|
||||||
#skip-if = !e10s # Bug 1373549
|
skip-if = !e10s # Bug 1373549
|
||||||
skip-if = true # temporarily disabled for bug 1193394
|
|
||||||
[browser_ContentSearch.js]
|
[browser_ContentSearch.js]
|
||||||
support-files =
|
support-files =
|
||||||
contentSearch.js
|
contentSearch.js
|
||||||
|
@ -1565,30 +1565,6 @@ Animation::GetRenderedDocument() const
|
|||||||
return mEffect->AsKeyframeEffect()->GetRenderedDocument();
|
return mEffect->AsKeyframeEffect()->GetRenderedDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncFinishNotification : public MicroTaskRunnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit AsyncFinishNotification(Animation* aAnimation)
|
|
||||||
: MicroTaskRunnable()
|
|
||||||
, mAnimation(aAnimation)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual void Run(AutoSlowOperation& aAso) override
|
|
||||||
{
|
|
||||||
mAnimation->DoFinishNotificationImmediately(this);
|
|
||||||
mAnimation = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool Suppressed() override
|
|
||||||
{
|
|
||||||
nsIGlobalObject* global = mAnimation->GetOwnerGlobal();
|
|
||||||
return global && global->IsInSyncOperation();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RefPtr<Animation> mAnimation;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Animation::DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag)
|
Animation::DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag)
|
||||||
{
|
{
|
||||||
@ -1596,8 +1572,11 @@ Animation::DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag)
|
|||||||
|
|
||||||
if (aSyncNotifyFlag == SyncNotifyFlag::Sync) {
|
if (aSyncNotifyFlag == SyncNotifyFlag::Sync) {
|
||||||
DoFinishNotificationImmediately();
|
DoFinishNotificationImmediately();
|
||||||
} else if (!mFinishNotificationTask) {
|
} else if (!mFinishNotificationTask.IsPending()) {
|
||||||
RefPtr<MicroTaskRunnable> runnable = new AsyncFinishNotification(this);
|
RefPtr<nsRunnableMethod<Animation>> runnable =
|
||||||
|
NewRunnableMethod("dom::Animation::DoFinishNotificationImmediately",
|
||||||
|
this,
|
||||||
|
&Animation::DoFinishNotificationImmediately);
|
||||||
context->DispatchToMicroTask(do_AddRef(runnable));
|
context->DispatchToMicroTask(do_AddRef(runnable));
|
||||||
mFinishNotificationTask = runnable.forget();
|
mFinishNotificationTask = runnable.forget();
|
||||||
}
|
}
|
||||||
@ -1620,13 +1599,9 @@ Animation::MaybeResolveFinishedPromise()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Animation::DoFinishNotificationImmediately(MicroTaskRunnable* aAsync)
|
Animation::DoFinishNotificationImmediately()
|
||||||
{
|
{
|
||||||
if (aAsync && aAsync != mFinishNotificationTask) {
|
mFinishNotificationTask.Revoke();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mFinishNotificationTask = nullptr;
|
|
||||||
|
|
||||||
if (PlayState() != AnimationPlayState::Finished) {
|
if (PlayState() != AnimationPlayState::Finished) {
|
||||||
return;
|
return;
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
#include "mozilla/AnimationPerformanceWarning.h"
|
#include "mozilla/AnimationPerformanceWarning.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/CycleCollectedJSContext.h"
|
|
||||||
#include "mozilla/DOMEventTargetHelper.h"
|
#include "mozilla/DOMEventTargetHelper.h"
|
||||||
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
|
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
@ -45,7 +44,6 @@ struct AnimationRule;
|
|||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class AsyncFinishNotification;
|
|
||||||
class CSSAnimation;
|
class CSSAnimation;
|
||||||
class CSSTransition;
|
class CSSTransition;
|
||||||
|
|
||||||
@ -451,8 +449,7 @@ protected:
|
|||||||
void ResetFinishedPromise();
|
void ResetFinishedPromise();
|
||||||
void MaybeResolveFinishedPromise();
|
void MaybeResolveFinishedPromise();
|
||||||
void DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag);
|
void DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag);
|
||||||
friend class AsyncFinishNotification;
|
void DoFinishNotificationImmediately();
|
||||||
void DoFinishNotificationImmediately(MicroTaskRunnable* aAsync = nullptr);
|
|
||||||
void DispatchPlaybackEvent(const nsAString& aName);
|
void DispatchPlaybackEvent(const nsAString& aName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -545,7 +542,7 @@ protected:
|
|||||||
// getAnimations() list.
|
// getAnimations() list.
|
||||||
bool mIsRelevant;
|
bool mIsRelevant;
|
||||||
|
|
||||||
RefPtr<MicroTaskRunnable> mFinishNotificationTask;
|
nsRevocableEventPtr<nsRunnableMethod<Animation>> mFinishNotificationTask;
|
||||||
// True if mFinished is resolved or would be resolved if mFinished has
|
// True if mFinished is resolved or would be resolved if mFinished has
|
||||||
// yet to be created. This is not set when mFinished is rejected since
|
// yet to be created. This is not set when mFinished is rejected since
|
||||||
// in that case mFinished is immediately reset to represent a new current
|
// in that case mFinished is immediately reset to represent a new current
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "DocumentTimeline.h"
|
#include "DocumentTimeline.h"
|
||||||
#include "mozilla/ScopeExit.h"
|
#include "mozilla/ScopeExit.h"
|
||||||
#include "mozilla/dom/DocumentTimelineBinding.h"
|
#include "mozilla/dom/DocumentTimelineBinding.h"
|
||||||
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "AnimationUtils.h"
|
#include "AnimationUtils.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsDOMMutationObserver.h"
|
#include "nsDOMMutationObserver.h"
|
||||||
@ -159,11 +160,14 @@ DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime)
|
|||||||
|
|
||||||
// https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events,
|
// https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events,
|
||||||
// step2.
|
// step2.
|
||||||
|
// FIXME: This needs to be replaced with nsAutoMicroTask.
|
||||||
// Note that this should be done before nsAutoAnimationMutationBatch. If
|
// Note that this should be done before nsAutoAnimationMutationBatch. If
|
||||||
// PerformMicroTaskCheckpoint was called before nsAutoAnimationMutationBatch
|
// PerformMicroTaskCheckpoint was called before nsAutoAnimationMutationBatch
|
||||||
// is destroyed, some mutation records might not be delivered in this
|
// is destroyed, some mutation records might not be delivered in this
|
||||||
// checkpoint.
|
// checkpoint.
|
||||||
nsAutoMicroTask mt;
|
auto autoPerformMicrotaskCheckpoint = MakeScopeExit([] {
|
||||||
|
Promise::PerformMicroTaskCheckpoint();
|
||||||
|
});
|
||||||
nsAutoAnimationMutationBatch mb(mDocument);
|
nsAutoAnimationMutationBatch mb(mDocument);
|
||||||
|
|
||||||
for (Animation* animation = mAnimationOrder.getFirst(); animation;
|
for (Animation* animation = mAnimationOrder.getFirst(); animation;
|
||||||
|
@ -1067,7 +1067,7 @@ CustomElementReactionsStack::Enqueue(Element* aElement,
|
|||||||
|
|
||||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||||
RefPtr<BackupQueueMicroTask> bqmt = new BackupQueueMicroTask(this);
|
RefPtr<BackupQueueMicroTask> bqmt = new BackupQueueMicroTask(this);
|
||||||
context->DispatchToMicroTask(bqmt.forget());
|
context->DispatchMicroTaskRunnable(bqmt.forget());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -5871,10 +5871,10 @@ nsContentUtils::RunInStableState(already_AddRefed<nsIRunnable> aRunnable)
|
|||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
void
|
void
|
||||||
nsContentUtils::AddPendingIDBTransaction(already_AddRefed<nsIRunnable> aTransaction)
|
nsContentUtils::RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
|
MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
|
||||||
CycleCollectedJSContext::Get()->AddPendingIDBTransaction(Move(aTransaction));
|
CycleCollectedJSContext::Get()->RunInMetastableState(Move(aRunnable));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
@ -6933,16 +6933,9 @@ nsContentUtils::IsSubDocumentTabbable(nsIContent* aContent)
|
|||||||
contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
|
contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
|
||||||
|
|
||||||
// If there are 2 viewers for the current docshell, that
|
// If there are 2 viewers for the current docshell, that
|
||||||
// means the current document may be a zombie document.
|
// means the current document is a zombie document.
|
||||||
// While load and pageshow events are dispatched, zombie viewer is the old,
|
// Only navigate into the subdocument if it's not a zombie.
|
||||||
// to be hidden document.
|
return !zombieViewer;
|
||||||
if (zombieViewer) {
|
|
||||||
bool inOnLoad = false;
|
|
||||||
docShell->GetIsExecutingOnLoadHandler(&inOnLoad);
|
|
||||||
return inOnLoad;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -2031,12 +2031,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
static void RunInStableState(already_AddRefed<nsIRunnable> aRunnable);
|
static void RunInStableState(already_AddRefed<nsIRunnable> aRunnable);
|
||||||
|
|
||||||
/* Add a pending IDBTransaction to be cleaned up at the end of performing a
|
/* Add a "synchronous section", in the form of an nsIRunnable run once the
|
||||||
* microtask checkpoint.
|
* event loop has reached a "metastable state". |aRunnable| must not cause any
|
||||||
* See the step of "Cleanup Indexed Database Transactions" in
|
* queued events to be processed (i.e. must not spin the event loop).
|
||||||
* https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint
|
* We've reached a metastable state when the currently executing task or
|
||||||
|
* microtask has finished. This is not specced at this time.
|
||||||
|
* In practice this runs aRunnable once the currently executing task or
|
||||||
|
* microtask finishes. If called multiple times per microtask, all the
|
||||||
|
* runnables will be executed, in the order in which RunInMetastableState()
|
||||||
|
* was called
|
||||||
*/
|
*/
|
||||||
static void AddPendingIDBTransaction(already_AddRefed<nsIRunnable> aTransaction);
|
static void RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if we are doing StableState/MetastableState.
|
* Returns true if we are doing StableState/MetastableState.
|
||||||
|
@ -620,7 +620,7 @@ nsDOMMutationObserver::QueueMutationObserverMicroTask()
|
|||||||
|
|
||||||
RefPtr<MutationObserverMicroTask> momt =
|
RefPtr<MutationObserverMicroTask> momt =
|
||||||
new MutationObserverMicroTask();
|
new MutationObserverMicroTask();
|
||||||
ccjs->DispatchToMicroTask(momt.forget());
|
ccjs->DispatchMicroTaskRunnable(momt.forget());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -643,7 +643,7 @@ nsDOMMutationObserver::RescheduleForRun()
|
|||||||
|
|
||||||
RefPtr<MutationObserverMicroTask> momt =
|
RefPtr<MutationObserverMicroTask> momt =
|
||||||
new MutationObserverMicroTask();
|
new MutationObserverMicroTask();
|
||||||
ccjs->DispatchToMicroTask(momt.forget());
|
ccjs->DispatchMicroTaskRunnable(momt.forget());
|
||||||
sScheduledMutationObservers = new AutoTArray<RefPtr<nsDOMMutationObserver>, 4>;
|
sScheduledMutationObservers = new AutoTArray<RefPtr<nsDOMMutationObserver>, 4>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6715,6 +6715,12 @@ nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout,
|
|||||||
// point anyway, and the script context should have already reported
|
// point anyway, and the script context should have already reported
|
||||||
// the script error in the usual way - so we just drop it.
|
// the script error in the usual way - so we just drop it.
|
||||||
|
|
||||||
|
// Since we might be processing more timeouts, go ahead and flush the promise
|
||||||
|
// queue now before we do that. We need to do that while we're still in our
|
||||||
|
// "running JS is safe" state (e.g. mRunningTimeout is set, timeout->mRunning
|
||||||
|
// is false).
|
||||||
|
Promise::PerformMicroTaskCheckpoint();
|
||||||
|
|
||||||
if (trackNestingLevel) {
|
if (trackNestingLevel) {
|
||||||
TimeoutManager::SetNestingLevel(nestingLevel);
|
TimeoutManager::SetNestingLevel(nestingLevel);
|
||||||
}
|
}
|
||||||
|
@ -140,9 +140,11 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
|||||||
, mExceptionHandling(aExceptionHandling)
|
, mExceptionHandling(aExceptionHandling)
|
||||||
, mIsMainThread(NS_IsMainThread())
|
, mIsMainThread(NS_IsMainThread())
|
||||||
{
|
{
|
||||||
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
if (mIsMainThread) {
|
||||||
if (ccjs) {
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
ccjs->EnterMicroTask();
|
if (ccjs) {
|
||||||
|
ccjs->EnterMicroTask();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the caller's subject principal (if necessary) early, before we
|
// Compute the caller's subject principal (if necessary) early, before we
|
||||||
@ -349,9 +351,11 @@ CallbackObject::CallSetup::~CallSetup()
|
|||||||
|
|
||||||
// It is important that this is the last thing we do, after leaving the
|
// It is important that this is the last thing we do, after leaving the
|
||||||
// compartment and undoing all our entry/incumbent script changes
|
// compartment and undoing all our entry/incumbent script changes
|
||||||
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
if (mIsMainThread) {
|
||||||
if (ccjs) {
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
ccjs->LeaveMicroTask();
|
if (ccjs) {
|
||||||
|
ccjs->LeaveMicroTask();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1095,8 +1095,12 @@ EventListenerManager::HandleEventSubType(Listener* aListener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (NS_SUCCEEDED(result)) {
|
if (NS_SUCCEEDED(result)) {
|
||||||
nsAutoMicroTask mt;
|
if (mIsMainThreadELM) {
|
||||||
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (ccjs) {
|
||||||
|
ccjs->EnterMicroTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
// nsIDOMEvent::currentTarget is set in EventDispatcher.
|
// nsIDOMEvent::currentTarget is set in EventDispatcher.
|
||||||
if (listenerHolder.HasWebIDLCallback()) {
|
if (listenerHolder.HasWebIDLCallback()) {
|
||||||
ErrorResult rv;
|
ErrorResult rv;
|
||||||
@ -1106,6 +1110,12 @@ EventListenerManager::HandleEventSubType(Listener* aListener,
|
|||||||
} else {
|
} else {
|
||||||
result = listenerHolder.GetXPCOMCallback()->HandleEvent(aDOMEvent);
|
result = listenerHolder.GetXPCOMCallback()->HandleEvent(aDOMEvent);
|
||||||
}
|
}
|
||||||
|
if (mIsMainThreadELM) {
|
||||||
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (ccjs) {
|
||||||
|
ccjs->LeaveMicroTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -849,26 +849,22 @@ DispatchSuccessEvent(ResultHelper* aResultHelper,
|
|||||||
IDB_LOG_STRINGIFY(aEvent, kSuccessEventType));
|
IDB_LOG_STRINGIFY(aEvent, kSuccessEventType));
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT_IF(transaction,
|
|
||||||
transaction->IsOpen() && !transaction->IsAborted());
|
|
||||||
|
|
||||||
bool dummy;
|
bool dummy;
|
||||||
nsresult rv = request->DispatchEvent(aEvent, &dummy);
|
nsresult rv = request->DispatchEvent(aEvent, &dummy);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT_IF(transaction,
|
||||||
|
transaction->IsOpen() || transaction->IsAborted());
|
||||||
|
|
||||||
WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
|
WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
|
||||||
MOZ_ASSERT(internalEvent);
|
MOZ_ASSERT(internalEvent);
|
||||||
|
|
||||||
if (transaction &&
|
if (transaction &&
|
||||||
transaction->IsOpen()) {
|
transaction->IsOpen() &&
|
||||||
if (internalEvent->mFlags.mExceptionWasRaised) {
|
internalEvent->mFlags.mExceptionWasRaised) {
|
||||||
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
||||||
} else {
|
|
||||||
// To handle upgrade transaction.
|
|
||||||
transaction->Run();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ IDBFileHandle::Create(IDBMutableFile* aMutableFile,
|
|||||||
MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
|
MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> runnable = do_QueryObject(fileHandle);
|
nsCOMPtr<nsIRunnable> runnable = do_QueryObject(fileHandle);
|
||||||
nsContentUtils::AddPendingIDBTransaction(runnable.forget());
|
nsContentUtils::RunInMetastableState(runnable.forget());
|
||||||
|
|
||||||
fileHandle->mCreating = true;
|
fileHandle->mCreating = true;
|
||||||
|
|
||||||
|
@ -192,11 +192,15 @@ IDBTransaction::CreateVersionChange(
|
|||||||
|
|
||||||
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
|
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRunnable> runnable = do_QueryObject(transaction);
|
||||||
|
nsContentUtils::RunInMetastableState(runnable.forget());
|
||||||
|
|
||||||
transaction->NoteActiveTransaction();
|
transaction->NoteActiveTransaction();
|
||||||
|
|
||||||
transaction->mBackgroundActor.mVersionChangeBackgroundActor = aActor;
|
transaction->mBackgroundActor.mVersionChangeBackgroundActor = aActor;
|
||||||
transaction->mNextObjectStoreId = aNextObjectStoreId;
|
transaction->mNextObjectStoreId = aNextObjectStoreId;
|
||||||
transaction->mNextIndexId = aNextIndexId;
|
transaction->mNextIndexId = aNextIndexId;
|
||||||
|
transaction->mCreating = true;
|
||||||
|
|
||||||
aDatabase->RegisterTransaction(transaction);
|
aDatabase->RegisterTransaction(transaction);
|
||||||
transaction->mRegistered = true;
|
transaction->mRegistered = true;
|
||||||
@ -246,7 +250,7 @@ IDBTransaction::Create(JSContext* aCx, IDBDatabase* aDatabase,
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> runnable = do_QueryObject(transaction);
|
nsCOMPtr<nsIRunnable> runnable = do_QueryObject(transaction);
|
||||||
nsContentUtils::AddPendingIDBTransaction(runnable.forget());
|
nsContentUtils::RunInMetastableState(runnable.forget());
|
||||||
|
|
||||||
transaction->mCreating = true;
|
transaction->mCreating = true;
|
||||||
|
|
||||||
|
@ -510,6 +510,126 @@ Promise::ReportRejectedPromise(JSContext* aCx, JS::HandleObject aPromise)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Promise::PerformMicroTaskCheckpoint()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||||
|
|
||||||
|
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||||
|
|
||||||
|
// On the main thread, we always use the main promise micro task queue.
|
||||||
|
std::queue<nsCOMPtr<nsIRunnable>>& microtaskQueue =
|
||||||
|
context->GetPromiseMicroTaskQueue();
|
||||||
|
|
||||||
|
if (microtaskQueue.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoSlowOperation aso;
|
||||||
|
|
||||||
|
do {
|
||||||
|
nsCOMPtr<nsIRunnable> runnable = microtaskQueue.front().forget();
|
||||||
|
MOZ_ASSERT(runnable);
|
||||||
|
|
||||||
|
// This function can re-enter, so we remove the element before calling.
|
||||||
|
microtaskQueue.pop();
|
||||||
|
nsresult rv = runnable->Run();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
aso.CheckForInterrupt();
|
||||||
|
context->AfterProcessMicrotask();
|
||||||
|
} while (!microtaskQueue.empty());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Promise::IsWorkerDebuggerMicroTaskEmpty()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
|
||||||
|
|
||||||
|
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||||
|
if (!context) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::queue<nsCOMPtr<nsIRunnable>>* microtaskQueue =
|
||||||
|
&context->GetDebuggerPromiseMicroTaskQueue();
|
||||||
|
|
||||||
|
return microtaskQueue->empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Promise::PerformWorkerMicroTaskCheckpoint()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
|
||||||
|
|
||||||
|
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||||
|
if (!context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// For a normal microtask checkpoint, we try to use the debugger microtask
|
||||||
|
// queue first. If the debugger queue is empty, we use the normal microtask
|
||||||
|
// queue instead.
|
||||||
|
std::queue<nsCOMPtr<nsIRunnable>>* microtaskQueue =
|
||||||
|
&context->GetDebuggerPromiseMicroTaskQueue();
|
||||||
|
|
||||||
|
if (microtaskQueue->empty()) {
|
||||||
|
microtaskQueue = &context->GetPromiseMicroTaskQueue();
|
||||||
|
if (microtaskQueue->empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRunnable> runnable = microtaskQueue->front().forget();
|
||||||
|
MOZ_ASSERT(runnable);
|
||||||
|
|
||||||
|
// This function can re-enter, so we remove the element before calling.
|
||||||
|
microtaskQueue->pop();
|
||||||
|
nsresult rv = runnable->Run();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context->AfterProcessMicrotask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Promise::PerformWorkerDebuggerMicroTaskCheckpoint()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
|
||||||
|
|
||||||
|
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||||
|
if (!context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// For a debugger microtask checkpoint, we always use the debugger microtask
|
||||||
|
// queue.
|
||||||
|
std::queue<nsCOMPtr<nsIRunnable>>* microtaskQueue =
|
||||||
|
&context->GetDebuggerPromiseMicroTaskQueue();
|
||||||
|
|
||||||
|
if (microtaskQueue->empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRunnable> runnable = microtaskQueue->front().forget();
|
||||||
|
MOZ_ASSERT(runnable);
|
||||||
|
|
||||||
|
// This function can re-enter, so we remove the element before calling.
|
||||||
|
microtaskQueue->pop();
|
||||||
|
nsresult rv = runnable->Run();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context->AfterProcessMicrotask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
Promise::GlobalJSObject() const
|
Promise::GlobalJSObject() const
|
||||||
{
|
{
|
||||||
|
@ -104,6 +104,15 @@ public:
|
|||||||
// specializations in the .cpp for
|
// specializations in the .cpp for
|
||||||
// the T values we support.
|
// the T values we support.
|
||||||
|
|
||||||
|
// Called by DOM to let us execute our callbacks. May be called recursively.
|
||||||
|
// Returns true if at least one microtask was processed.
|
||||||
|
static bool PerformMicroTaskCheckpoint();
|
||||||
|
|
||||||
|
static void PerformWorkerMicroTaskCheckpoint();
|
||||||
|
|
||||||
|
static void PerformWorkerDebuggerMicroTaskCheckpoint();
|
||||||
|
static bool IsWorkerDebuggerMicroTaskEmpty();
|
||||||
|
|
||||||
// WebIDL
|
// WebIDL
|
||||||
|
|
||||||
nsIGlobalObject* GetParentObject() const
|
nsIGlobalObject* GetParentObject() const
|
||||||
|
@ -186,7 +186,7 @@ function promiseAsync_SyncXHR()
|
|||||||
xhr.open("GET", "testXHR.txt", false);
|
xhr.open("GET", "testXHR.txt", false);
|
||||||
xhr.send(null);
|
xhr.send(null);
|
||||||
|
|
||||||
ok(!handlerExecuted, "Sync XHR should not trigger microtask execution.");
|
todo(!handlerExecuted, "Sync XHR should not trigger microtask execution.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function promiseDoubleThen() {
|
function promiseDoubleThen() {
|
||||||
|
@ -830,6 +830,8 @@ AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMP
|
|||||||
AutoSlowOperation::AutoSlowOperation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
AutoSlowOperation::AutoSlowOperation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
||||||
: AutoJSAPI()
|
: AutoJSAPI()
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
@ -838,12 +840,9 @@ AutoSlowOperation::AutoSlowOperation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMP
|
|||||||
void
|
void
|
||||||
AutoSlowOperation::CheckForInterrupt()
|
AutoSlowOperation::CheckForInterrupt()
|
||||||
{
|
{
|
||||||
// For now we support only main thread!
|
// JS_CheckForInterrupt expects us to be in a compartment.
|
||||||
if (mIsMainThread) {
|
JSAutoCompartment ac(cx(), xpc::UnprivilegedJunkScope());
|
||||||
// JS_CheckForInterrupt expects us to be in a compartment.
|
JS_CheckForInterrupt(cx());
|
||||||
JSAutoCompartment ac(cx(), xpc::UnprivilegedJunkScope());
|
|
||||||
JS_CheckForInterrupt(cx());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -293,6 +293,7 @@ protected:
|
|||||||
// AutoJSAPI, so Init must NOT be called on subclasses that use this.
|
// AutoJSAPI, so Init must NOT be called on subclasses that use this.
|
||||||
AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread, Type aType);
|
AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread, Type aType);
|
||||||
|
|
||||||
|
private:
|
||||||
mozilla::Maybe<JSAutoRequest> mAutoRequest;
|
mozilla::Maybe<JSAutoRequest> mAutoRequest;
|
||||||
mozilla::Maybe<JSAutoNullableCompartment> mAutoNullableCompartment;
|
mozilla::Maybe<JSAutoNullableCompartment> mAutoNullableCompartment;
|
||||||
JSContext *mCx;
|
JSContext *mCx;
|
||||||
@ -301,7 +302,6 @@ protected:
|
|||||||
bool mIsMainThread;
|
bool mIsMainThread;
|
||||||
Maybe<JS::WarningReporter> mOldWarningReporter;
|
Maybe<JS::WarningReporter> mOldWarningReporter;
|
||||||
|
|
||||||
private:
|
|
||||||
void InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal,
|
void InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal,
|
||||||
JSContext* aCx, bool aIsMainThread);
|
JSContext* aCx, bool aIsMainThread);
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@ public:
|
|||||||
MOZ_ASSERT(mWorkerPrivate);
|
MOZ_ASSERT(mWorkerPrivate);
|
||||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
|
||||||
if (mPendingPromisesCount || !mKeepAliveToken) {
|
if (mPendingPromisesCount) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mCallback) {
|
if (mCallback) {
|
||||||
@ -365,18 +365,6 @@ private:
|
|||||||
mSelfRef = nullptr;
|
mSelfRef = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MaybeDoneRunner : public MicroTaskRunnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit MaybeDoneRunner(KeepAliveHandler* aHandler) : mHandler(aHandler) {}
|
|
||||||
virtual void Run(AutoSlowOperation& aAso) override
|
|
||||||
{
|
|
||||||
mHandler->MaybeDone();
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<KeepAliveHandler> mHandler;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RemovePromise(ExtendableEventResult aResult)
|
RemovePromise(ExtendableEventResult aResult)
|
||||||
{
|
{
|
||||||
@ -400,7 +388,10 @@ private:
|
|||||||
CycleCollectedJSContext* cx = CycleCollectedJSContext::Get();
|
CycleCollectedJSContext* cx = CycleCollectedJSContext::Get();
|
||||||
MOZ_ASSERT(cx);
|
MOZ_ASSERT(cx);
|
||||||
|
|
||||||
RefPtr<MaybeDoneRunner> r = new MaybeDoneRunner(this);
|
RefPtr<nsIRunnable> r =
|
||||||
|
NewRunnableMethod("dom::KeepAliveHandler::MaybeDone",
|
||||||
|
this,
|
||||||
|
&KeepAliveHandler::MaybeDone);
|
||||||
cx->DispatchToMicroTask(r.forget());
|
cx->DispatchToMicroTask(r.forget());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1052,10 +1052,6 @@ public:
|
|||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR_INHERITED(WorkerJSContext, CycleCollectedJSContext);
|
MOZ_COUNT_CTOR_INHERITED(WorkerJSContext, CycleCollectedJSContext);
|
||||||
MOZ_ASSERT(aWorkerPrivate);
|
MOZ_ASSERT(aWorkerPrivate);
|
||||||
// Magical number 2. Workers have the base recursion depth 1, and normal
|
|
||||||
// runnables run at level 2, and we don't want to process microtasks
|
|
||||||
// at any other level.
|
|
||||||
SetTargetedMicroTaskRecursionDepth(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~WorkerJSContext()
|
~WorkerJSContext()
|
||||||
@ -1109,14 +1105,26 @@ public:
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void DispatchToMicroTask(already_AddRefed<MicroTaskRunnable> aRunnable) override
|
virtual void AfterProcessTask(uint32_t aRecursionDepth) override
|
||||||
{
|
{
|
||||||
RefPtr<MicroTaskRunnable> runnable(aRunnable);
|
// Only perform the Promise microtask checkpoint on the outermost event
|
||||||
|
// loop. Don't run it, for example, during sync XHR or importScripts.
|
||||||
|
if (aRecursionDepth == 2) {
|
||||||
|
CycleCollectedJSContext::AfterProcessTask(aRecursionDepth);
|
||||||
|
} else if (aRecursionDepth > 2) {
|
||||||
|
AutoDisableMicroTaskCheckpoint disableMicroTaskCheckpoint;
|
||||||
|
CycleCollectedJSContext::AfterProcessTask(aRecursionDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable) override
|
||||||
|
{
|
||||||
|
RefPtr<nsIRunnable> runnable(aRunnable);
|
||||||
|
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
MOZ_ASSERT(runnable);
|
MOZ_ASSERT(runnable);
|
||||||
|
|
||||||
std::queue<RefPtr<MicroTaskRunnable>>* microTaskQueue = nullptr;
|
std::queue<nsCOMPtr<nsIRunnable>>* microTaskQueue = nullptr;
|
||||||
|
|
||||||
JSContext* cx = GetCurrentWorkerThreadJSContext();
|
JSContext* cx = GetCurrentWorkerThreadJSContext();
|
||||||
NS_ASSERTION(cx, "This should never be null!");
|
NS_ASSERTION(cx, "This should never be null!");
|
||||||
@ -1125,16 +1133,16 @@ public:
|
|||||||
NS_ASSERTION(global, "This should never be null!");
|
NS_ASSERTION(global, "This should never be null!");
|
||||||
|
|
||||||
// On worker threads, if the current global is the worker global, we use the
|
// On worker threads, if the current global is the worker global, we use the
|
||||||
// main micro task queue. Otherwise, the current global must be
|
// main promise micro task queue. Otherwise, the current global must be
|
||||||
// either the debugger global or a debugger sandbox, and we use the debugger
|
// either the debugger global or a debugger sandbox, and we use the debugger
|
||||||
// micro task queue instead.
|
// promise micro task queue instead.
|
||||||
if (IsWorkerGlobal(global)) {
|
if (IsWorkerGlobal(global)) {
|
||||||
microTaskQueue = &GetMicroTaskQueue();
|
microTaskQueue = &mPromiseMicroTaskQueue;
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(IsWorkerDebuggerGlobal(global) ||
|
MOZ_ASSERT(IsWorkerDebuggerGlobal(global) ||
|
||||||
IsWorkerDebuggerSandbox(global));
|
IsWorkerDebuggerSandbox(global));
|
||||||
|
|
||||||
microTaskQueue = &GetDebuggerMicroTaskQueue();
|
microTaskQueue = &mDebuggerPromiseMicroTaskQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
microTaskQueue->push(runnable.forget());
|
microTaskQueue->push(runnable.forget());
|
||||||
|
@ -3259,10 +3259,8 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
|
|||||||
static_cast<nsIRunnable*>(runnable)->Run();
|
static_cast<nsIRunnable*>(runnable)->Run();
|
||||||
runnable->Release();
|
runnable->Release();
|
||||||
|
|
||||||
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
// Flush the promise queue.
|
||||||
if (ccjs) {
|
Promise::PerformWorkerDebuggerMicroTaskCheckpoint();
|
||||||
ccjs->PerformDebuggerMicroTaskCheckpoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debuggerRunnablesPending) {
|
if (debuggerRunnablesPending) {
|
||||||
WorkerDebuggerGlobalScope* globalScope = DebuggerGlobalScope();
|
WorkerDebuggerGlobalScope* globalScope = DebuggerGlobalScope();
|
||||||
@ -4346,12 +4344,9 @@ WorkerPrivate::EnterDebuggerEventLoop()
|
|||||||
{
|
{
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
|
|
||||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
|
||||||
std::queue<RefPtr<MicroTaskRunnable>>& debuggerMtQueue =
|
|
||||||
context->GetDebuggerMicroTaskQueue();
|
|
||||||
while (mControlQueue.IsEmpty() &&
|
while (mControlQueue.IsEmpty() &&
|
||||||
!(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty()) &&
|
!(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty()) &&
|
||||||
debuggerMtQueue.empty()) {
|
Promise::IsWorkerDebuggerMicroTaskEmpty()) {
|
||||||
WaitForWorkerEvents();
|
WaitForWorkerEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4359,9 +4354,8 @@ WorkerPrivate::EnterDebuggerEventLoop()
|
|||||||
|
|
||||||
// XXXkhuey should we abort JS on the stack here if we got Abort above?
|
// XXXkhuey should we abort JS on the stack here if we got Abort above?
|
||||||
}
|
}
|
||||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
if (!Promise::IsWorkerDebuggerMicroTaskEmpty()) {
|
||||||
if (context) {
|
Promise::PerformWorkerDebuggerMicroTaskCheckpoint();
|
||||||
context->PerformDebuggerMicroTaskCheckpoint();
|
|
||||||
}
|
}
|
||||||
if (debuggerRunnablesPending) {
|
if (debuggerRunnablesPending) {
|
||||||
// Start the periodic GC timer if it is not already running.
|
// Start the periodic GC timer if it is not already running.
|
||||||
@ -4379,10 +4373,8 @@ WorkerPrivate::EnterDebuggerEventLoop()
|
|||||||
static_cast<nsIRunnable*>(runnable)->Run();
|
static_cast<nsIRunnable*>(runnable)->Run();
|
||||||
runnable->Release();
|
runnable->Release();
|
||||||
|
|
||||||
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
// Flush the promise queue.
|
||||||
if (ccjs) {
|
Promise::PerformWorkerDebuggerMicroTaskCheckpoint();
|
||||||
ccjs->PerformDebuggerMicroTaskCheckpoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now *might* be a good time to GC. Let the JS engine make the decision.
|
// Now *might* be a good time to GC. Let the JS engine make the decision.
|
||||||
if (JS::CurrentGlobalOrNull(cx)) {
|
if (JS::CurrentGlobalOrNull(cx)) {
|
||||||
@ -4747,8 +4739,8 @@ WorkerPrivate::RunExpiredTimeouts(JSContext* aCx)
|
|||||||
|
|
||||||
RefPtr<Function> callback = info->mHandler->GetCallback();
|
RefPtr<Function> callback = info->mHandler->GetCallback();
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
nsAutoMicroTask mt;
|
// scope for the AutoEntryScript, so it comes off the stack before we do
|
||||||
|
// Promise::PerformMicroTaskCheckpoint.
|
||||||
AutoEntryScript aes(global, reason, false);
|
AutoEntryScript aes(global, reason, false);
|
||||||
|
|
||||||
// Evaluate the timeout expression.
|
// Evaluate the timeout expression.
|
||||||
@ -4783,6 +4775,10 @@ WorkerPrivate::RunExpiredTimeouts(JSContext* aCx)
|
|||||||
rv.SuppressException();
|
rv.SuppressException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since we might be processing more timeouts, go ahead and flush
|
||||||
|
// the promise queue now before we do that.
|
||||||
|
Promise::PerformWorkerMicroTaskCheckpoint();
|
||||||
|
|
||||||
NS_ASSERTION(mRunningExpiredTimeouts, "Someone changed this!");
|
NS_ASSERTION(mRunningExpiredTimeouts, "Someone changed this!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,6 +1219,21 @@ XPCJSContext::BeforeProcessTask(bool aMightBlock)
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
// If ProcessNextEvent was called during a Promise "then" callback, we
|
||||||
|
// must process any pending microtasks before blocking in the event loop,
|
||||||
|
// otherwise we may deadlock until an event enters the queue later.
|
||||||
|
if (aMightBlock) {
|
||||||
|
if (Promise::PerformMicroTaskCheckpoint()) {
|
||||||
|
// If any microtask was processed, we post a dummy event in order to
|
||||||
|
// force the ProcessNextEvent call not to block. This is required
|
||||||
|
// to support nested event loops implemented using a pattern like
|
||||||
|
// "while (condition) thread.processNextEvent(true)", in case the
|
||||||
|
// condition is triggered here by a Promise "then" callback.
|
||||||
|
|
||||||
|
NS_DispatchToMainThread(new Runnable("Empty_microtask_runnable"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start the slow script timer.
|
// Start the slow script timer.
|
||||||
mSlowScriptCheckpoint = mozilla::TimeStamp::NowLoRes();
|
mSlowScriptCheckpoint = mozilla::TimeStamp::NowLoRes();
|
||||||
mSlowScriptSecondHalf = false;
|
mSlowScriptSecondHalf = false;
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
[event-dispatch-active-flag.html]
|
||||||
|
[Transactions are active during success handlers]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Transactions are active during success listeners]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Transactions are active during error handlers]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Transactions are active during error listeners]
|
||||||
|
expected: FAIL
|
||||||
|
|
@ -0,0 +1,10 @@
|
|||||||
|
[transaction-deactivation-timing.html]
|
||||||
|
[New transactions are not deactivated until after the microtask checkpoint]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[New transactions from microtask are still active through the microtask checkpoint]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Deactivation of new transactions happens at end of invocation]
|
||||||
|
expected: FAIL
|
||||||
|
|
@ -0,0 +1,4 @@
|
|||||||
|
[upgrade-transaction-deactivation-timing.html]
|
||||||
|
[Upgrade transactions are active in upgradeneeded callback and microtasks]
|
||||||
|
expected: FAIL
|
||||||
|
|
@ -0,0 +1,4 @@
|
|||||||
|
[upgrade-transaction-lifecycle-user-aborted.html]
|
||||||
|
[in a promise microtask after abort() is called, before the transaction abort event is fired]
|
||||||
|
expected: FAIL
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
[microtasks-and-constructors.html]
|
||||||
|
[Microtasks evaluate immediately when the stack is empty inside the parser]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Microtasks evaluate afterward when the stack is not empty using createElement()]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Microtasks evaluate afterward when the stack is not empty using the constructor]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Microtasks evaluate afterward when the stack is not empty due to upgrades]
|
||||||
|
expected: FAIL
|
||||||
|
|
@ -0,0 +1,4 @@
|
|||||||
|
[task_microtask_ordering.html]
|
||||||
|
[Level 1 bossfight (synthetic click)]
|
||||||
|
expected: FAIL
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
[extendable-event-async-waituntil.https.html]
|
|
||||||
type: testharness
|
|
||||||
[Test calling waitUntil in a different microtask without an existing extension throws]
|
|
||||||
expected: FAIL
|
|
@ -0,0 +1,3 @@
|
|||||||
|
[basic.html]
|
||||||
|
expected:
|
||||||
|
if e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
|
@ -0,0 +1,3 @@
|
|||||||
|
[bidi_ruby.html]
|
||||||
|
expected:
|
||||||
|
if e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
|
@ -0,0 +1,3 @@
|
|||||||
|
[u0041_first.html]
|
||||||
|
expected:
|
||||||
|
if e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
|
@ -0,0 +1,3 @@
|
|||||||
|
[u06E9_no_strong_dir.html]
|
||||||
|
expected:
|
||||||
|
if os == "mac": FAIL
|
@ -52,7 +52,7 @@ CycleCollectedJSContext::CycleCollectedJSContext()
|
|||||||
, mRuntime(nullptr)
|
, mRuntime(nullptr)
|
||||||
, mJSContext(nullptr)
|
, mJSContext(nullptr)
|
||||||
, mDoingStableStates(false)
|
, mDoingStableStates(false)
|
||||||
, mTargetedMicroTaskRecursionDepth(0)
|
, mDisableMicroTaskCheckpoint(false)
|
||||||
, mMicroTaskLevel(0)
|
, mMicroTaskLevel(0)
|
||||||
, mMicroTaskRecursionDepth(0)
|
, mMicroTaskRecursionDepth(0)
|
||||||
{
|
{
|
||||||
@ -77,8 +77,8 @@ CycleCollectedJSContext::~CycleCollectedJSContext()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Last chance to process any events.
|
// Last chance to process any events.
|
||||||
CleanupIDBTransactions(mBaseRecursionDepth);
|
ProcessMetastableStateQueue(mBaseRecursionDepth);
|
||||||
MOZ_ASSERT(mPendingIDBTransactions.IsEmpty());
|
MOZ_ASSERT(mMetastableStateEvents.IsEmpty());
|
||||||
|
|
||||||
ProcessStableStateQueue();
|
ProcessStableStateQueue();
|
||||||
MOZ_ASSERT(mStableStateEvents.IsEmpty());
|
MOZ_ASSERT(mStableStateEvents.IsEmpty());
|
||||||
@ -86,8 +86,8 @@ CycleCollectedJSContext::~CycleCollectedJSContext()
|
|||||||
// Clear mPendingException first, since it might be cycle collected.
|
// Clear mPendingException first, since it might be cycle collected.
|
||||||
mPendingException = nullptr;
|
mPendingException = nullptr;
|
||||||
|
|
||||||
MOZ_ASSERT(mDebuggerMicroTaskQueue.empty());
|
MOZ_ASSERT(mDebuggerPromiseMicroTaskQueue.empty());
|
||||||
MOZ_ASSERT(mPendingMicroTaskRunnables.empty());
|
MOZ_ASSERT(mPromiseMicroTaskQueue.empty());
|
||||||
|
|
||||||
mUncaughtRejections.reset();
|
mUncaughtRejections.reset();
|
||||||
mConsumedRejections.reset();
|
mConsumedRejections.reset();
|
||||||
@ -181,14 +181,15 @@ CycleCollectedJSContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
class PromiseJobRunnable final : public MicroTaskRunnable
|
class PromiseJobRunnable final : public Runnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PromiseJobRunnable(JS::HandleObject aCallback,
|
PromiseJobRunnable(JS::HandleObject aCallback,
|
||||||
JS::HandleObject aAllocationSite,
|
JS::HandleObject aAllocationSite,
|
||||||
nsIGlobalObject* aIncumbentGlobal)
|
nsIGlobalObject* aIncumbentGlobal)
|
||||||
:mCallback(
|
: Runnable("PromiseJobRunnable")
|
||||||
new PromiseJobCallback(aCallback, aAllocationSite, aIncumbentGlobal))
|
, mCallback(
|
||||||
|
new PromiseJobCallback(aCallback, aAllocationSite, aIncumbentGlobal))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,21 +198,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Run(AutoSlowOperation& aAso) override
|
NS_IMETHOD
|
||||||
|
Run() override
|
||||||
{
|
{
|
||||||
JSObject* callback = mCallback->CallbackPreserveColor();
|
JSObject* callback = mCallback->CallbackPreserveColor();
|
||||||
nsIGlobalObject* global = callback ? xpc::NativeGlobal(callback) : nullptr;
|
nsIGlobalObject* global = callback ? xpc::NativeGlobal(callback) : nullptr;
|
||||||
if (global && !global->IsDying()) {
|
if (global && !global->IsDying()) {
|
||||||
mCallback->Call("promise callback");
|
mCallback->Call("promise callback");
|
||||||
aAso.CheckForInterrupt();
|
|
||||||
}
|
}
|
||||||
}
|
return NS_OK;
|
||||||
|
|
||||||
virtual bool Suppressed() override
|
|
||||||
{
|
|
||||||
nsIGlobalObject* global =
|
|
||||||
xpc::NativeGlobal(mCallback->CallbackPreserveColor());
|
|
||||||
return global && global->IsInSyncOperation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -245,7 +240,7 @@ CycleCollectedJSContext::EnqueuePromiseJobCallback(JSContext* aCx,
|
|||||||
if (aIncumbentGlobal) {
|
if (aIncumbentGlobal) {
|
||||||
global = xpc::NativeGlobal(aIncumbentGlobal);
|
global = xpc::NativeGlobal(aIncumbentGlobal);
|
||||||
}
|
}
|
||||||
RefPtr<MicroTaskRunnable> runnable = new PromiseJobRunnable(aJob, aAllocationSite, global);
|
nsCOMPtr<nsIRunnable> runnable = new PromiseJobRunnable(aJob, aAllocationSite, global);
|
||||||
self->DispatchToMicroTask(runnable.forget());
|
self->DispatchToMicroTask(runnable.forget());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -286,18 +281,18 @@ CycleCollectedJSContext::SetPendingException(Exception* aException)
|
|||||||
mPendingException = aException;
|
mPendingException = aException;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::queue<RefPtr<MicroTaskRunnable>>&
|
std::queue<nsCOMPtr<nsIRunnable>>&
|
||||||
CycleCollectedJSContext::GetMicroTaskQueue()
|
CycleCollectedJSContext::GetPromiseMicroTaskQueue()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mJSContext);
|
MOZ_ASSERT(mJSContext);
|
||||||
return mPendingMicroTaskRunnables;
|
return mPromiseMicroTaskQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::queue<RefPtr<MicroTaskRunnable>>&
|
std::queue<nsCOMPtr<nsIRunnable>>&
|
||||||
CycleCollectedJSContext::GetDebuggerMicroTaskQueue()
|
CycleCollectedJSContext::GetDebuggerPromiseMicroTaskQueue()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mJSContext);
|
MOZ_ASSERT(mJSContext);
|
||||||
return mDebuggerMicroTaskQueue;
|
return mDebuggerPromiseMicroTaskQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -317,24 +312,24 @@ CycleCollectedJSContext::ProcessStableStateQueue()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CycleCollectedJSContext::CleanupIDBTransactions(uint32_t aRecursionDepth)
|
CycleCollectedJSContext::ProcessMetastableStateQueue(uint32_t aRecursionDepth)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mJSContext);
|
MOZ_ASSERT(mJSContext);
|
||||||
MOZ_RELEASE_ASSERT(!mDoingStableStates);
|
MOZ_RELEASE_ASSERT(!mDoingStableStates);
|
||||||
mDoingStableStates = true;
|
mDoingStableStates = true;
|
||||||
|
|
||||||
nsTArray<PendingIDBTransactionData> localQueue = Move(mPendingIDBTransactions);
|
nsTArray<RunInMetastableStateData> localQueue = Move(mMetastableStateEvents);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < localQueue.Length(); ++i)
|
for (uint32_t i = 0; i < localQueue.Length(); ++i)
|
||||||
{
|
{
|
||||||
PendingIDBTransactionData& data = localQueue[i];
|
RunInMetastableStateData& data = localQueue[i];
|
||||||
if (data.mRecursionDepth != aRecursionDepth) {
|
if (data.mRecursionDepth != aRecursionDepth) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIRunnable> transaction = data.mTransaction.forget();
|
nsCOMPtr<nsIRunnable> runnable = data.mRunnable.forget();
|
||||||
transaction->Run();
|
runnable->Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
localQueue.RemoveElementAt(i--);
|
localQueue.RemoveElementAt(i--);
|
||||||
@ -342,27 +337,11 @@ CycleCollectedJSContext::CleanupIDBTransactions(uint32_t aRecursionDepth)
|
|||||||
|
|
||||||
// If the queue has events in it now, they were added from something we called,
|
// If the queue has events in it now, they were added from something we called,
|
||||||
// so they belong at the end of the queue.
|
// so they belong at the end of the queue.
|
||||||
localQueue.AppendElements(mPendingIDBTransactions);
|
localQueue.AppendElements(mMetastableStateEvents);
|
||||||
localQueue.SwapElements(mPendingIDBTransactions);
|
localQueue.SwapElements(mMetastableStateEvents);
|
||||||
mDoingStableStates = false;
|
mDoingStableStates = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CycleCollectedJSContext::BeforeProcessTask(bool aMightBlock)
|
|
||||||
{
|
|
||||||
// If ProcessNextEvent was called during a microtask callback, we
|
|
||||||
// must process any pending microtasks before blocking in the event loop,
|
|
||||||
// otherwise we may deadlock until an event enters the queue later.
|
|
||||||
if (aMightBlock && PerformMicroTaskCheckPoint()) {
|
|
||||||
// If any microtask was processed, we post a dummy event in order to
|
|
||||||
// force the ProcessNextEvent call not to block. This is required
|
|
||||||
// to support nested event loops implemented using a pattern like
|
|
||||||
// "while (condition) thread.processNextEvent(true)", in case the
|
|
||||||
// condition is triggered here by a Promise "then" callback.
|
|
||||||
NS_DispatchToMainThread(new Runnable("BeforeProcessTask"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth)
|
CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth)
|
||||||
{
|
{
|
||||||
@ -370,8 +349,19 @@ CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth)
|
|||||||
|
|
||||||
// See HTML 6.1.4.2 Processing model
|
// See HTML 6.1.4.2 Processing model
|
||||||
|
|
||||||
|
// Execute any events that were waiting for a microtask to complete.
|
||||||
|
// This is not (yet) in the spec.
|
||||||
|
ProcessMetastableStateQueue(aRecursionDepth);
|
||||||
|
|
||||||
// Step 4.1: Execute microtasks.
|
// Step 4.1: Execute microtasks.
|
||||||
PerformMicroTaskCheckPoint();
|
if (!mDisableMicroTaskCheckpoint) {
|
||||||
|
PerformMicroTaskCheckPoint();
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
Promise::PerformMicroTaskCheckpoint();
|
||||||
|
} else {
|
||||||
|
Promise::PerformWorkerMicroTaskCheckpoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Step 4.2 Execute any events that were waiting for a stable state.
|
// Step 4.2 Execute any events that were waiting for a stable state.
|
||||||
ProcessStableStateQueue();
|
ProcessStableStateQueue();
|
||||||
@ -381,12 +371,10 @@ CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CycleCollectedJSContext::AfterProcessMicrotasks()
|
CycleCollectedJSContext::AfterProcessMicrotask()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mJSContext);
|
MOZ_ASSERT(mJSContext);
|
||||||
// Cleanup Indexed Database transactions:
|
AfterProcessMicrotask(RecursionDepth());
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint
|
|
||||||
CleanupIDBTransactions(RecursionDepth());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CycleCollectedJSContext::IsIdleGCTaskNeeded()
|
void CycleCollectedJSContext::IsIdleGCTaskNeeded()
|
||||||
@ -419,6 +407,16 @@ void CycleCollectedJSContext::IsIdleGCTaskNeeded()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CycleCollectedJSContext::AfterProcessMicrotask(uint32_t aRecursionDepth)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mJSContext);
|
||||||
|
|
||||||
|
// Between microtasks, execute any events that were waiting for a microtask
|
||||||
|
// to complete.
|
||||||
|
ProcessMetastableStateQueue(aRecursionDepth);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
CycleCollectedJSContext::RecursionDepth()
|
CycleCollectedJSContext::RecursionDepth()
|
||||||
{
|
{
|
||||||
@ -433,12 +431,12 @@ CycleCollectedJSContext::RunInStableState(already_AddRefed<nsIRunnable>&& aRunna
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CycleCollectedJSContext::AddPendingIDBTransaction(already_AddRefed<nsIRunnable>&& aTransaction)
|
CycleCollectedJSContext::RunInMetastableState(already_AddRefed<nsIRunnable>&& aRunnable)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mJSContext);
|
MOZ_ASSERT(mJSContext);
|
||||||
|
|
||||||
PendingIDBTransactionData data;
|
RunInMetastableStateData data;
|
||||||
data.mTransaction = aTransaction;
|
data.mRunnable = aRunnable;
|
||||||
|
|
||||||
MOZ_ASSERT(mOwningThread);
|
MOZ_ASSERT(mOwningThread);
|
||||||
data.mRecursionDepth = RecursionDepth();
|
data.mRecursionDepth = RecursionDepth();
|
||||||
@ -455,19 +453,18 @@ CycleCollectedJSContext::AddPendingIDBTransaction(already_AddRefed<nsIRunnable>&
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mPendingIDBTransactions.AppendElement(Move(data));
|
mMetastableStateEvents.AppendElement(Move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CycleCollectedJSContext::DispatchToMicroTask(
|
CycleCollectedJSContext::DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable)
|
||||||
already_AddRefed<MicroTaskRunnable> aRunnable)
|
|
||||||
{
|
{
|
||||||
RefPtr<MicroTaskRunnable> runnable(aRunnable);
|
RefPtr<nsIRunnable> runnable(aRunnable);
|
||||||
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(runnable);
|
MOZ_ASSERT(runnable);
|
||||||
|
|
||||||
mPendingMicroTaskRunnables.push(runnable.forget());
|
mPromiseMicroTaskQueue.push(runnable.forget());
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncMutationHandler final : public mozilla::Runnable
|
class AsyncMutationHandler final : public mozilla::Runnable
|
||||||
@ -485,61 +482,41 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
void
|
||||||
CycleCollectedJSContext::PerformMicroTaskCheckPoint()
|
CycleCollectedJSContext::PerformMicroTaskCheckPoint()
|
||||||
{
|
{
|
||||||
if (mPendingMicroTaskRunnables.empty() && mDebuggerMicroTaskQueue.empty()) {
|
if (mPendingMicroTaskRunnables.empty()) {
|
||||||
AfterProcessMicrotasks();
|
|
||||||
// Nothing to do, return early.
|
// Nothing to do, return early.
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t currentDepth = RecursionDepth();
|
uint32_t currentDepth = RecursionDepth();
|
||||||
if (mMicroTaskRecursionDepth >= currentDepth) {
|
if (mMicroTaskRecursionDepth >= currentDepth) {
|
||||||
// We are already executing microtasks for the current recursion depth.
|
// We are already executing microtasks for the current recursion depth.
|
||||||
return false;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (mTargetedMicroTaskRecursionDepth != 0 &&
|
|
||||||
mTargetedMicroTaskRecursionDepth != currentDepth) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_IsMainThread() && !nsContentUtils::IsSafeToRunScript()) {
|
if (NS_IsMainThread() && !nsContentUtils::IsSafeToRunScript()) {
|
||||||
// Special case for main thread where DOM mutations may happen when
|
// Special case for main thread where DOM mutations may happen when
|
||||||
// it is not safe to run scripts.
|
// it is not safe to run scripts.
|
||||||
nsContentUtils::AddScriptRunner(new AsyncMutationHandler());
|
nsContentUtils::AddScriptRunner(new AsyncMutationHandler());
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::AutoRestore<uint32_t> restore(mMicroTaskRecursionDepth);
|
mozilla::AutoRestore<uint32_t> restore(mMicroTaskRecursionDepth);
|
||||||
MOZ_ASSERT(currentDepth > 0);
|
MOZ_ASSERT(currentDepth > 0);
|
||||||
mMicroTaskRecursionDepth = currentDepth;
|
mMicroTaskRecursionDepth = currentDepth;
|
||||||
|
|
||||||
bool didProcess = false;
|
|
||||||
AutoSlowOperation aso;
|
AutoSlowOperation aso;
|
||||||
|
|
||||||
std::queue<RefPtr<MicroTaskRunnable>> suppressed;
|
std::queue<RefPtr<MicroTaskRunnable>> suppressed;
|
||||||
for (;;) {
|
while (!mPendingMicroTaskRunnables.empty()) {
|
||||||
RefPtr<MicroTaskRunnable> runnable;
|
RefPtr<MicroTaskRunnable> runnable =
|
||||||
if (!mDebuggerMicroTaskQueue.empty()) {
|
mPendingMicroTaskRunnables.front().forget();
|
||||||
runnable = mDebuggerMicroTaskQueue.front().forget();
|
mPendingMicroTaskRunnables.pop();
|
||||||
mDebuggerMicroTaskQueue.pop();
|
|
||||||
} else if (!mPendingMicroTaskRunnables.empty()) {
|
|
||||||
runnable = mPendingMicroTaskRunnables.front().forget();
|
|
||||||
mPendingMicroTaskRunnables.pop();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runnable->Suppressed()) {
|
if (runnable->Suppressed()) {
|
||||||
// Microtasks in worker shall never be suppressed.
|
|
||||||
// Otherwise, mPendingMicroTaskRunnables will be replaced later with
|
|
||||||
// all suppressed tasks in mDebuggerMicroTaskQueue unexpectedly.
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
suppressed.push(runnable);
|
suppressed.push(runnable);
|
||||||
} else {
|
} else {
|
||||||
didProcess = true;
|
|
||||||
runnable->Run(aso);
|
runnable->Run(aso);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -549,37 +526,13 @@ CycleCollectedJSContext::PerformMicroTaskCheckPoint()
|
|||||||
// for some time, but no longer than spinning the event loop nestedly
|
// for some time, but no longer than spinning the event loop nestedly
|
||||||
// (sync XHR, alert, etc.)
|
// (sync XHR, alert, etc.)
|
||||||
mPendingMicroTaskRunnables.swap(suppressed);
|
mPendingMicroTaskRunnables.swap(suppressed);
|
||||||
|
|
||||||
AfterProcessMicrotasks();
|
|
||||||
|
|
||||||
return didProcess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CycleCollectedJSContext::PerformDebuggerMicroTaskCheckpoint()
|
CycleCollectedJSContext::DispatchMicroTaskRunnable(
|
||||||
{
|
already_AddRefed<MicroTaskRunnable> aRunnable)
|
||||||
// Don't do normal microtask handling checks here, since whoever is calling
|
{
|
||||||
// this method is supposed to know what they are doing.
|
mPendingMicroTaskRunnables.push(aRunnable);
|
||||||
|
|
||||||
AutoSlowOperation aso;
|
|
||||||
for (;;) {
|
|
||||||
// For a debugger microtask checkpoint, we always use the debugger microtask
|
|
||||||
// queue.
|
|
||||||
std::queue<RefPtr<MicroTaskRunnable>>* microtaskQueue =
|
|
||||||
&GetDebuggerMicroTaskQueue();
|
|
||||||
|
|
||||||
if (microtaskQueue->empty()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<MicroTaskRunnable> runnable = microtaskQueue->front().forget();
|
|
||||||
MOZ_ASSERT(runnable);
|
|
||||||
|
|
||||||
// This function can re-enter, so we remove the element before calling.
|
|
||||||
microtaskQueue->pop();
|
|
||||||
runnable->Run(aso);
|
|
||||||
}
|
|
||||||
|
|
||||||
AfterProcessMicrotasks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -103,6 +103,9 @@ protected:
|
|||||||
|
|
||||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||||
|
|
||||||
|
std::queue<nsCOMPtr<nsIRunnable>> mPromiseMicroTaskQueue;
|
||||||
|
std::queue<nsCOMPtr<nsIRunnable>> mDebuggerPromiseMicroTaskQueue;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MOZ_IS_CLASS_INIT
|
MOZ_IS_CLASS_INIT
|
||||||
void InitializeCommon();
|
void InitializeCommon();
|
||||||
@ -118,11 +121,11 @@ private:
|
|||||||
JS::PromiseRejectionHandlingState state,
|
JS::PromiseRejectionHandlingState state,
|
||||||
void* aData);
|
void* aData);
|
||||||
|
|
||||||
void AfterProcessMicrotasks();
|
void AfterProcessMicrotask(uint32_t aRecursionDepth);
|
||||||
public:
|
public:
|
||||||
void ProcessStableStateQueue();
|
void ProcessStableStateQueue();
|
||||||
private:
|
private:
|
||||||
void CleanupIDBTransactions(uint32_t aRecursionDepth);
|
void ProcessMetastableStateQueue(uint32_t aRecursionDepth);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum DeferredFinalizeType {
|
enum DeferredFinalizeType {
|
||||||
@ -139,8 +142,8 @@ public:
|
|||||||
already_AddRefed<dom::Exception> GetPendingException() const;
|
already_AddRefed<dom::Exception> GetPendingException() const;
|
||||||
void SetPendingException(dom::Exception* aException);
|
void SetPendingException(dom::Exception* aException);
|
||||||
|
|
||||||
std::queue<RefPtr<MicroTaskRunnable>>& GetMicroTaskQueue();
|
std::queue<nsCOMPtr<nsIRunnable>>& GetPromiseMicroTaskQueue();
|
||||||
std::queue<RefPtr<MicroTaskRunnable>>& GetDebuggerMicroTaskQueue();
|
std::queue<nsCOMPtr<nsIRunnable>>& GetDebuggerPromiseMicroTaskQueue();
|
||||||
|
|
||||||
JSContext* Context() const
|
JSContext* Context() const
|
||||||
{
|
{
|
||||||
@ -154,19 +157,46 @@ public:
|
|||||||
return JS::RootingContext::get(mJSContext);
|
return JS::RootingContext::get(mJSContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTargetedMicroTaskRecursionDepth(uint32_t aDepth)
|
bool MicroTaskCheckpointDisabled() const
|
||||||
{
|
{
|
||||||
mTargetedMicroTaskRecursionDepth = aDepth;
|
return mDisableMicroTaskCheckpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisableMicroTaskCheckpoint(bool aDisable)
|
||||||
|
{
|
||||||
|
mDisableMicroTaskCheckpoint = aDisable;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MOZ_RAII AutoDisableMicroTaskCheckpoint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AutoDisableMicroTaskCheckpoint()
|
||||||
|
: mCCJSCX(CycleCollectedJSContext::Get())
|
||||||
|
{
|
||||||
|
mOldValue = mCCJSCX->MicroTaskCheckpointDisabled();
|
||||||
|
mCCJSCX->DisableMicroTaskCheckpoint(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AutoDisableMicroTaskCheckpoint()
|
||||||
|
{
|
||||||
|
mCCJSCX->DisableMicroTaskCheckpoint(mOldValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
CycleCollectedJSContext* mCCJSCX;
|
||||||
|
bool mOldValue;
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
JSContext* MaybeContext() const { return mJSContext; }
|
JSContext* MaybeContext() const { return mJSContext; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// nsThread entrypoints
|
// nsThread entrypoints
|
||||||
virtual void BeforeProcessTask(bool aMightBlock);
|
virtual void BeforeProcessTask(bool aMightBlock) { };
|
||||||
virtual void AfterProcessTask(uint32_t aRecursionDepth);
|
virtual void AfterProcessTask(uint32_t aRecursionDepth);
|
||||||
|
|
||||||
|
// microtask processor entry point
|
||||||
|
void AfterProcessMicrotask();
|
||||||
|
|
||||||
// Check whether we need an idle GC task.
|
// Check whether we need an idle GC task.
|
||||||
void IsIdleGCTaskNeeded();
|
void IsIdleGCTaskNeeded();
|
||||||
|
|
||||||
@ -174,15 +204,16 @@ public:
|
|||||||
|
|
||||||
// Run in stable state (call through nsContentUtils)
|
// Run in stable state (call through nsContentUtils)
|
||||||
void RunInStableState(already_AddRefed<nsIRunnable>&& aRunnable);
|
void RunInStableState(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||||
|
// This isn't in the spec at all yet, but this gets the behavior we want for IDB.
|
||||||
void AddPendingIDBTransaction(already_AddRefed<nsIRunnable>&& aTransaction);
|
// Runs after the current microtask completes.
|
||||||
|
void RunInMetastableState(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||||
|
|
||||||
// Get the current thread's CycleCollectedJSContext. Returns null if there
|
// Get the current thread's CycleCollectedJSContext. Returns null if there
|
||||||
// isn't one.
|
// isn't one.
|
||||||
static CycleCollectedJSContext* Get();
|
static CycleCollectedJSContext* Get();
|
||||||
|
|
||||||
// Queue an async microtask to the current main or worker thread.
|
// Queue an async microtask to the current main or worker thread.
|
||||||
virtual void DispatchToMicroTask(already_AddRefed<MicroTaskRunnable> aRunnable);
|
virtual void DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable);
|
||||||
|
|
||||||
// Call EnterMicroTask when you're entering JS execution.
|
// Call EnterMicroTask when you're entering JS execution.
|
||||||
// Usually the best way to do this is to use nsAutoMicroTask.
|
// Usually the best way to do this is to use nsAutoMicroTask.
|
||||||
@ -213,9 +244,9 @@ public:
|
|||||||
mMicroTaskLevel = aLevel;
|
mMicroTaskLevel = aLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PerformMicroTaskCheckPoint();
|
void PerformMicroTaskCheckPoint();
|
||||||
|
|
||||||
void PerformDebuggerMicroTaskCheckpoint();
|
void DispatchMicroTaskRunnable(already_AddRefed<MicroTaskRunnable> aRunnable);
|
||||||
|
|
||||||
bool IsInStableOrMetaStableState()
|
bool IsInStableOrMetaStableState()
|
||||||
{
|
{
|
||||||
@ -250,25 +281,21 @@ private:
|
|||||||
nsCOMPtr<dom::Exception> mPendingException;
|
nsCOMPtr<dom::Exception> mPendingException;
|
||||||
nsThread* mOwningThread; // Manual refcounting to avoid include hell.
|
nsThread* mOwningThread; // Manual refcounting to avoid include hell.
|
||||||
|
|
||||||
struct PendingIDBTransactionData
|
struct RunInMetastableStateData
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIRunnable> mTransaction;
|
nsCOMPtr<nsIRunnable> mRunnable;
|
||||||
uint32_t mRecursionDepth;
|
uint32_t mRecursionDepth;
|
||||||
};
|
};
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsIRunnable>> mStableStateEvents;
|
nsTArray<nsCOMPtr<nsIRunnable>> mStableStateEvents;
|
||||||
nsTArray<PendingIDBTransactionData> mPendingIDBTransactions;
|
nsTArray<RunInMetastableStateData> mMetastableStateEvents;
|
||||||
uint32_t mBaseRecursionDepth;
|
uint32_t mBaseRecursionDepth;
|
||||||
bool mDoingStableStates;
|
bool mDoingStableStates;
|
||||||
|
|
||||||
// If set to none 0, microtasks will be processed only when recursion depth
|
bool mDisableMicroTaskCheckpoint;
|
||||||
// is the set value.
|
|
||||||
uint32_t mTargetedMicroTaskRecursionDepth;
|
|
||||||
|
|
||||||
uint32_t mMicroTaskLevel;
|
uint32_t mMicroTaskLevel;
|
||||||
|
|
||||||
std::queue<RefPtr<MicroTaskRunnable>> mPendingMicroTaskRunnables;
|
std::queue<RefPtr<MicroTaskRunnable>> mPendingMicroTaskRunnables;
|
||||||
std::queue<RefPtr<MicroTaskRunnable>> mDebuggerMicroTaskQueue;
|
|
||||||
|
|
||||||
uint32_t mMicroTaskRecursionDepth;
|
uint32_t mMicroTaskRecursionDepth;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user