Bug 1392540 - Keep running debugger Promise while debugging workers. r=baku
MozReview-Commit-ID: JsA0Y943egB
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -535,16 +535,32 @@ Promise::PerformMicroTaskCheckpoint()
}
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;
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -107,16 +107,17 @@ public:
// 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
nsIGlobalObject* GetParentObject() const
{
return mGlobal;
}
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -6124,16 +6124,17 @@ WorkerPrivate::EnterDebuggerEventLoop()
AssertIsOnWorkerThread();
JSContext* cx = GetJSContext();
MOZ_ASSERT(cx);
uint32_t currentEventLoopLevel = ++mDebuggerEventLoopLevel;
while (currentEventLoopLevel <= mDebuggerEventLoopLevel) {
+
bool debuggerRunnablesPending = false;
{
MutexAutoLock lock(mMutex);
debuggerRunnablesPending = !mDebuggerQueue.IsEmpty();
}
@@ -6142,25 +6143,28 @@ WorkerPrivate::EnterDebuggerEventLoop()
SetGCTimerMode(IdleTimer);
}
// Wait for something to do
{
MutexAutoLock lock(mMutex);
while (mControlQueue.IsEmpty() &&
- !(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty())) {
+ !(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty()) &&
+ Promise::IsWorkerDebuggerMicroTaskEmpty()) {
WaitForWorkerEvents();
}
ProcessAllControlRunnablesLocked();
// XXXkhuey should we abort JS on the stack here if we got Abort above?
}
-
+ if (!Promise::IsWorkerDebuggerMicroTaskEmpty()) {
+ Promise::PerformWorkerDebuggerMicroTaskCheckpoint();
+ }
if (debuggerRunnablesPending) {
// Start the periodic GC timer if it is not already running.
SetGCTimerMode(PeriodicTimer);
WorkerRunnable* runnable = nullptr;
{
MutexAutoLock lock(mMutex);
--- a/dom/workers/test/WorkerDebugger_promise_debugger.js
+++ b/dom/workers/test/WorkerDebugger_promise_debugger.js
@@ -17,14 +17,18 @@ self.onmessage = function (event) {
}
// This then-handler should be executed inside the nested event loop,
// within the context of the debugger's global.
Promise.resolve().then(function () {
postMessage("resumed");
leaveEventLoop();
});
};
- postMessage("paused");
+ // Test bug 1392540 where DOM Promises from debugger principal
+ // where frozen while hitting a worker breakpoint.
+ Promise.resolve().then(() => {
+ postMessage("paused");
+ });
enterEventLoop();
};
postMessage("resolved");
});
};