Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / workers / WorkerRunnable.cpp
blob14a3e5e3f97b507ef63caa6d23cc339362c5332c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "WorkerRunnable.h"
9 #include "WorkerScope.h"
10 #include "js/RootingAPI.h"
11 #include "jsapi.h"
12 #include "jsfriendapi.h"
13 #include "mozilla/AlreadyAddRefed.h"
14 #include "mozilla/AppShutdown.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/CycleCollectedJSContext.h"
17 #include "mozilla/DebugOnly.h"
18 #include "mozilla/ErrorResult.h"
19 #include "mozilla/Logging.h"
20 #include "mozilla/Maybe.h"
21 #include "mozilla/Telemetry.h"
22 #include "mozilla/TelemetryHistogramEnums.h"
23 #include "mozilla/TimeStamp.h"
24 #include "mozilla/Unused.h"
25 #include "mozilla/dom/ScriptSettings.h"
26 #include "mozilla/dom/Worker.h"
27 #include "mozilla/dom/WorkerCommon.h"
28 #include "nsDebug.h"
29 #include "nsGlobalWindowInner.h"
30 #include "nsID.h"
31 #include "nsIEventTarget.h"
32 #include "nsIGlobalObject.h"
33 #include "nsIRunnable.h"
34 #include "nsThreadUtils.h"
35 #include "nsWrapperCacheInlines.h"
37 namespace mozilla::dom {
39 static mozilla::LazyLogModule sWorkerRunnableLog("WorkerRunnable");
41 #ifdef LOG
42 # undef LOG
43 #endif
44 #define LOG(args) MOZ_LOG(sWorkerRunnableLog, LogLevel::Verbose, args);
46 namespace {
48 const nsIID kWorkerRunnableIID = {
49 0x320cc0b5,
50 0xef12,
51 0x4084,
52 {0x88, 0x6e, 0xca, 0x6a, 0x81, 0xe4, 0x1d, 0x68}};
54 } // namespace
56 #ifdef DEBUG
57 WorkerRunnable::WorkerRunnable(WorkerPrivate* aWorkerPrivate, const char* aName,
58 Target aTarget)
59 : mWorkerPrivate(aWorkerPrivate),
60 mTarget(aTarget),
61 # ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
62 mName(aName),
63 # endif
64 mCallingCancelWithinRun(false) {
65 LOG(("WorkerRunnable::WorkerRunnable [%p]", this));
66 MOZ_ASSERT(aWorkerPrivate);
68 #endif
70 bool WorkerRunnable::IsDebuggerRunnable() const { return false; }
72 nsIGlobalObject* WorkerRunnable::DefaultGlobalObject() const {
73 if (IsDebuggerRunnable()) {
74 return mWorkerPrivate->DebuggerGlobalScope();
75 } else {
76 return mWorkerPrivate->GlobalScope();
80 bool WorkerRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
81 #ifdef DEBUG
82 MOZ_ASSERT(aWorkerPrivate);
84 switch (mTarget) {
85 case ParentThread:
86 aWorkerPrivate->AssertIsOnWorkerThread();
87 break;
89 case WorkerThread:
90 aWorkerPrivate->AssertIsOnParentThread();
91 break;
93 default:
94 MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
96 #endif
97 return true;
100 bool WorkerRunnable::Dispatch() {
101 bool ok = PreDispatch(mWorkerPrivate);
102 if (ok) {
103 ok = DispatchInternal();
105 PostDispatch(mWorkerPrivate, ok);
106 return ok;
109 bool WorkerRunnable::DispatchInternal() {
110 LOG(("WorkerRunnable::DispatchInternal [%p]", this));
111 RefPtr<WorkerRunnable> runnable(this);
113 if (mTarget == WorkerThread) {
114 if (IsDebuggerRunnable()) {
115 return NS_SUCCEEDED(
116 mWorkerPrivate->DispatchDebuggerRunnable(runnable.forget()));
117 } else {
118 return NS_SUCCEEDED(mWorkerPrivate->Dispatch(runnable.forget()));
122 MOZ_ASSERT(mTarget == ParentThread);
124 if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
125 return NS_SUCCEEDED(parent->Dispatch(runnable.forget()));
128 if (IsDebuggeeRunnable()) {
129 RefPtr<WorkerDebuggeeRunnable> debuggeeRunnable =
130 runnable.forget().downcast<WorkerDebuggeeRunnable>();
131 return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggeeToMainThread(
132 debuggeeRunnable.forget(), NS_DISPATCH_NORMAL));
135 return NS_SUCCEEDED(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
138 void WorkerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
139 bool aDispatchResult) {
140 MOZ_ASSERT(aWorkerPrivate);
142 #ifdef DEBUG
143 switch (mTarget) {
144 case ParentThread:
145 aWorkerPrivate->AssertIsOnWorkerThread();
146 break;
148 case WorkerThread:
149 aWorkerPrivate->AssertIsOnParentThread();
150 break;
152 default:
153 MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
155 #endif
158 bool WorkerRunnable::PreRun(WorkerPrivate* aWorkerPrivate) { return true; }
160 void WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
161 bool aRunResult) {
162 MOZ_ASSERT(aCx);
163 MOZ_ASSERT(aWorkerPrivate);
165 #ifdef DEBUG
166 switch (mTarget) {
167 case ParentThread:
168 aWorkerPrivate->AssertIsOnParentThread();
169 break;
171 case WorkerThread:
172 aWorkerPrivate->AssertIsOnWorkerThread();
173 break;
175 default:
176 MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
178 #endif
181 // static
182 WorkerRunnable* WorkerRunnable::FromRunnable(nsIRunnable* aRunnable) {
183 MOZ_ASSERT(aRunnable);
185 WorkerRunnable* runnable;
186 nsresult rv = aRunnable->QueryInterface(kWorkerRunnableIID,
187 reinterpret_cast<void**>(&runnable));
188 if (NS_FAILED(rv)) {
189 return nullptr;
192 MOZ_ASSERT(runnable);
193 return runnable;
196 NS_IMPL_ADDREF(WorkerRunnable)
197 NS_IMPL_RELEASE(WorkerRunnable)
199 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
200 NS_IMETHODIMP
201 WorkerRunnable::GetName(nsACString& aName) {
202 if (mName) {
203 aName.AssignASCII(mName);
204 } else {
205 aName.Truncate();
207 return NS_OK;
209 #endif
211 NS_INTERFACE_MAP_BEGIN(WorkerRunnable)
212 NS_INTERFACE_MAP_ENTRY(nsIRunnable)
213 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
214 NS_INTERFACE_MAP_ENTRY(nsINamed)
215 #endif
216 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable)
217 // kWorkerRunnableIID is special in that it does not AddRef its result.
218 if (aIID.Equals(kWorkerRunnableIID)) {
219 *aInstancePtr = this;
220 return NS_OK;
221 } else
222 NS_INTERFACE_MAP_END
224 NS_IMETHODIMP
225 WorkerRunnable::Run() {
226 LOG(("WorkerRunnable::Run [%p]", this));
227 bool targetIsWorkerThread = mTarget == WorkerThread;
229 #ifdef DEBUG
230 if (targetIsWorkerThread) {
231 mWorkerPrivate->AssertIsOnWorkerThread();
232 } else {
233 MOZ_ASSERT(mTarget == ParentThread);
234 mWorkerPrivate->AssertIsOnParentThread();
236 #endif
238 if (targetIsWorkerThread && !mCallingCancelWithinRun &&
239 mWorkerPrivate->CancelBeforeWorkerScopeConstructed()) {
240 mCallingCancelWithinRun = true;
241 Cancel();
242 mCallingCancelWithinRun = false;
243 return NS_OK;
246 bool result = PreRun(mWorkerPrivate);
247 if (!result) {
248 MOZ_ASSERT(targetIsWorkerThread,
249 "The only PreRun implementation that can fail is "
250 "ScriptExecutorRunnable");
251 mWorkerPrivate->AssertIsOnWorkerThread();
252 MOZ_ASSERT(!JS_IsExceptionPending(mWorkerPrivate->GetJSContext()));
253 // We can't enter a useful realm on the JSContext here; just pass it
254 // in as-is.
255 PostRun(mWorkerPrivate->GetJSContext(), mWorkerPrivate, false);
256 return NS_ERROR_FAILURE;
259 // Track down the appropriate global, if any, to use for the AutoEntryScript.
260 nsCOMPtr<nsIGlobalObject> globalObject;
261 bool isMainThread = !targetIsWorkerThread && !mWorkerPrivate->GetParent();
262 MOZ_ASSERT(isMainThread == NS_IsMainThread());
263 RefPtr<WorkerPrivate> kungFuDeathGrip;
264 if (targetIsWorkerThread) {
265 globalObject = mWorkerPrivate->GetCurrentEventLoopGlobal();
266 if (!globalObject) {
267 globalObject = DefaultGlobalObject();
268 // Our worker thread may not be in a good state here if there is no
269 // JSContext avaliable. The way this manifests itself is that
270 // globalObject ends up null (though it's not clear to me how we can be
271 // running runnables at all when DefaultGlobalObject() is returning
272 // false!) and then when we try to init the AutoJSAPI either
273 // CycleCollectedJSContext::Get() returns null or it has a null JSContext.
274 // In any case, we used to have a check for
275 // GetCurrentWorkerThreadJSContext() being non-null here and that seems to
276 // avoid the problem, so let's keep doing that check even if we don't need
277 // the JSContext here at all.
278 if (NS_WARN_IF(!globalObject && !GetCurrentWorkerThreadJSContext())) {
279 return NS_ERROR_FAILURE;
283 // We may still not have a globalObject here: in the case of
284 // CompileScriptRunnable, we don't actually create the global object until
285 // we have the script data, which happens in a syncloop under
286 // CompileScriptRunnable::WorkerRun, so we can't assert that it got created
287 // in the PreRun call above.
288 } else {
289 kungFuDeathGrip = mWorkerPrivate;
290 if (isMainThread) {
291 globalObject = nsGlobalWindowInner::Cast(mWorkerPrivate->GetWindow());
292 } else {
293 globalObject = mWorkerPrivate->GetParent()->GlobalScope();
297 // We might run script as part of WorkerRun, so we need an AutoEntryScript.
298 // This is part of the HTML spec for workers at:
299 // http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker
300 // If we don't have a globalObject we have to use an AutoJSAPI instead, but
301 // this is OK as we won't be running script in these circumstances.
302 Maybe<mozilla::dom::AutoJSAPI> maybeJSAPI;
303 Maybe<mozilla::dom::AutoEntryScript> aes;
304 JSContext* cx;
305 AutoJSAPI* jsapi;
306 if (globalObject) {
307 aes.emplace(globalObject, "Worker runnable", isMainThread);
308 jsapi = aes.ptr();
309 cx = aes->cx();
310 } else {
311 maybeJSAPI.emplace();
312 maybeJSAPI->Init();
313 jsapi = maybeJSAPI.ptr();
314 cx = jsapi->cx();
317 // Note that we can't assert anything about
318 // mWorkerPrivate->ParentEventTargetRef()->GetWrapper()
319 // existing, since it may in fact have been GCed (and we may be one of the
320 // runnables cleaning up the worker as a result).
322 // If we are on the parent thread and that thread is not the main thread,
323 // then we must be a dedicated worker (because there are no
324 // Shared/ServiceWorkers whose parent is itself a worker) and then we
325 // definitely have a globalObject. If it _is_ the main thread, globalObject
326 // can be null for workers started from JSMs or other non-window contexts,
327 // sadly.
328 MOZ_ASSERT_IF(!targetIsWorkerThread && !isMainThread,
329 mWorkerPrivate->IsDedicatedWorker() && globalObject);
331 // If we're on the parent thread we might be in a null realm in the
332 // situation described above when globalObject is null. Make sure to enter
333 // the realm of the worker's reflector if there is one. There might
334 // not be one if we're just starting to compile the script for this worker.
335 Maybe<JSAutoRealm> ar;
336 if (!targetIsWorkerThread && mWorkerPrivate->IsDedicatedWorker() &&
337 mWorkerPrivate->ParentEventTargetRef()->GetWrapper()) {
338 JSObject* wrapper = mWorkerPrivate->ParentEventTargetRef()->GetWrapper();
340 // If we're on the parent thread and have a reflector and a globalObject,
341 // then the realms of cx, globalObject, and the worker's reflector
342 // should all match.
343 MOZ_ASSERT_IF(globalObject,
344 js::GetNonCCWObjectRealm(wrapper) == js::GetContextRealm(cx));
345 MOZ_ASSERT_IF(globalObject,
346 js::GetNonCCWObjectRealm(wrapper) ==
347 js::GetNonCCWObjectRealm(
348 globalObject->GetGlobalJSObjectPreserveColor()));
350 // If we're on the parent thread and have a reflector, then our
351 // JSContext had better be either in the null realm (and hence
352 // have no globalObject) or in the realm of our reflector.
353 MOZ_ASSERT(!js::GetContextRealm(cx) ||
354 js::GetNonCCWObjectRealm(wrapper) == js::GetContextRealm(cx),
355 "Must either be in the null compartment or in our reflector "
356 "compartment");
358 ar.emplace(cx, wrapper);
361 MOZ_ASSERT(!jsapi->HasException());
362 result = WorkerRun(cx, mWorkerPrivate);
363 jsapi->ReportException();
365 // We can't even assert that this didn't create our global, since in the case
366 // of CompileScriptRunnable it _does_.
368 // It would be nice to avoid passing a JSContext to PostRun, but in the case
369 // of ScriptExecutorRunnable we need to know the current compartment on the
370 // JSContext (the one we set up based on the global returned from PreRun) so
371 // that we can sanely do exception reporting. In particular, we want to make
372 // sure that we do our JS_SetPendingException while still in that compartment,
373 // because otherwise we might end up trying to create a cross-compartment
374 // wrapper when we try to move the JS exception from our runnable's
375 // ErrorResult to the JSContext, and that's not desirable in this case.
377 // We _could_ skip passing a JSContext here and then in
378 // ScriptExecutorRunnable::PostRun end up grabbing it from the WorkerPrivate
379 // and looking at its current compartment. But that seems like slightly weird
380 // action-at-a-distance...
382 // In any case, we do NOT try to change the compartment on the JSContext at
383 // this point; in the one case in which we could do that
384 // (CompileScriptRunnable) it actually doesn't matter which compartment we're
385 // in for PostRun.
386 PostRun(cx, mWorkerPrivate, result);
387 MOZ_ASSERT(!jsapi->HasException());
389 return result ? NS_OK : NS_ERROR_FAILURE;
392 nsresult WorkerRunnable::Cancel() {
393 LOG(("WorkerRunnable::Cancel [%p]", this));
394 return NS_OK;
397 void WorkerDebuggerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
398 bool aDispatchResult) {}
400 WorkerSyncRunnable::WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
401 nsIEventTarget* aSyncLoopTarget,
402 const char* aName)
403 : WorkerRunnable(aWorkerPrivate, aName, WorkerThread),
404 mSyncLoopTarget(aSyncLoopTarget) {
405 #ifdef DEBUG
406 if (mSyncLoopTarget) {
407 mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
409 #endif
412 WorkerSyncRunnable::WorkerSyncRunnable(
413 WorkerPrivate* aWorkerPrivate, nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
414 const char* aName)
415 : WorkerRunnable(aWorkerPrivate, aName, WorkerThread),
416 mSyncLoopTarget(std::move(aSyncLoopTarget)) {
417 #ifdef DEBUG
418 if (mSyncLoopTarget) {
419 mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
421 #endif
424 WorkerSyncRunnable::~WorkerSyncRunnable() = default;
426 bool WorkerSyncRunnable::DispatchInternal() {
427 if (mSyncLoopTarget) {
428 RefPtr<WorkerSyncRunnable> runnable(this);
429 return NS_SUCCEEDED(
430 mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
433 return WorkerRunnable::DispatchInternal();
436 void MainThreadWorkerSyncRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
437 bool aDispatchResult) {}
439 MainThreadStopSyncLoopRunnable::MainThreadStopSyncLoopRunnable(
440 WorkerPrivate* aWorkerPrivate, nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
441 nsresult aResult)
442 : WorkerSyncRunnable(aWorkerPrivate, std::move(aSyncLoopTarget)),
443 mResult(aResult) {
444 LOG(("MainThreadStopSyncLoopRunnable::MainThreadStopSyncLoopRunnable [%p]",
445 this));
447 AssertIsOnMainThread();
448 #ifdef DEBUG
449 mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
450 #endif
453 nsresult MainThreadStopSyncLoopRunnable::Cancel() {
454 LOG(("MainThreadStopSyncLoopRunnable::Cancel [%p]", this));
455 nsresult rv = Run();
456 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Run() failed");
458 return rv;
461 bool MainThreadStopSyncLoopRunnable::WorkerRun(JSContext* aCx,
462 WorkerPrivate* aWorkerPrivate) {
463 aWorkerPrivate->AssertIsOnWorkerThread();
464 MOZ_ASSERT(mSyncLoopTarget);
466 nsCOMPtr<nsIEventTarget> syncLoopTarget;
467 mSyncLoopTarget.swap(syncLoopTarget);
469 aWorkerPrivate->StopSyncLoop(syncLoopTarget, mResult);
470 return true;
473 bool MainThreadStopSyncLoopRunnable::DispatchInternal() {
474 MOZ_ASSERT(mSyncLoopTarget);
476 RefPtr<MainThreadStopSyncLoopRunnable> runnable(this);
477 return NS_SUCCEEDED(
478 mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
481 void MainThreadStopSyncLoopRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
482 bool aDispatchResult) {}
484 #ifdef DEBUG
485 WorkerControlRunnable::WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
486 const char* aName, Target aTarget)
487 : WorkerRunnable(aWorkerPrivate, aName, aTarget) {
488 MOZ_ASSERT(aWorkerPrivate);
490 #endif
492 nsresult WorkerControlRunnable::Cancel() {
493 LOG(("WorkerControlRunnable::Cancel [%p]", this));
494 if (NS_FAILED(Run())) {
495 NS_WARNING("WorkerControlRunnable::Run() failed.");
498 return NS_OK;
501 bool WorkerControlRunnable::DispatchInternal() {
502 RefPtr<WorkerControlRunnable> runnable(this);
504 if (mTarget == WorkerThread) {
505 return NS_SUCCEEDED(
506 mWorkerPrivate->DispatchControlRunnable(runnable.forget()));
509 if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
510 return NS_SUCCEEDED(parent->DispatchControlRunnable(runnable.forget()));
513 return NS_SUCCEEDED(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
516 WorkerMainThreadRunnable::WorkerMainThreadRunnable(
517 WorkerPrivate* aWorkerPrivate, const nsACString& aTelemetryKey)
518 : mozilla::Runnable("dom::WorkerMainThreadRunnable"),
519 mWorkerPrivate(aWorkerPrivate),
520 mTelemetryKey(aTelemetryKey) {
521 mWorkerPrivate->AssertIsOnWorkerThread();
524 WorkerMainThreadRunnable::~WorkerMainThreadRunnable() = default;
526 void WorkerMainThreadRunnable::Dispatch(WorkerStatus aFailStatus,
527 mozilla::ErrorResult& aRv) {
528 mWorkerPrivate->AssertIsOnWorkerThread();
530 TimeStamp startTime = TimeStamp::NowLoRes();
532 AutoSyncLoopHolder syncLoop(mWorkerPrivate, aFailStatus);
534 mSyncLoopTarget = syncLoop.GetSerialEventTarget();
535 if (!mSyncLoopTarget) {
536 // SyncLoop creation can fail if the worker is shutting down.
537 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
538 return;
541 DebugOnly<nsresult> rv = mWorkerPrivate->DispatchToMainThread(this);
542 MOZ_ASSERT(
543 NS_SUCCEEDED(rv),
544 "Should only fail after xpcom-shutdown-threads and we're gone by then");
546 bool success = NS_SUCCEEDED(syncLoop.Run());
548 Telemetry::Accumulate(
549 Telemetry::SYNC_WORKER_OPERATION, mTelemetryKey,
550 static_cast<uint32_t>(
551 (TimeStamp::NowLoRes() - startTime).ToMilliseconds()));
553 Unused << startTime; // Shut the compiler up.
555 if (!success) {
556 aRv.ThrowUncatchableException();
560 NS_IMETHODIMP
561 WorkerMainThreadRunnable::Run() {
562 AssertIsOnMainThread();
564 // This shouldn't be necessary once we're better about making sure no workers
565 // are created during shutdown in earlier phases.
566 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
567 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
570 bool runResult = MainThreadRun();
572 RefPtr<MainThreadStopSyncLoopRunnable> response =
573 new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
574 std::move(mSyncLoopTarget),
575 runResult ? NS_OK : NS_ERROR_FAILURE);
577 MOZ_ALWAYS_TRUE(response->Dispatch());
579 return NS_OK;
582 bool WorkerSameThreadRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
583 aWorkerPrivate->AssertIsOnWorkerThread();
584 return true;
587 void WorkerSameThreadRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
588 bool aDispatchResult) {
589 aWorkerPrivate->AssertIsOnWorkerThread();
592 WorkerProxyToMainThreadRunnable::WorkerProxyToMainThreadRunnable()
593 : mozilla::Runnable("dom::WorkerProxyToMainThreadRunnable") {}
595 WorkerProxyToMainThreadRunnable::~WorkerProxyToMainThreadRunnable() = default;
597 bool WorkerProxyToMainThreadRunnable::Dispatch(WorkerPrivate* aWorkerPrivate) {
598 MOZ_ASSERT(aWorkerPrivate);
599 aWorkerPrivate->AssertIsOnWorkerThread();
601 RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
602 aWorkerPrivate, "WorkerProxyToMainThreadRunnable");
603 if (NS_WARN_IF(!workerRef)) {
604 RunBackOnWorkerThreadForCleanup(aWorkerPrivate);
605 return false;
608 MOZ_ASSERT(!mWorkerRef);
609 mWorkerRef = new ThreadSafeWorkerRef(workerRef);
611 if (ForMessaging()
612 ? NS_WARN_IF(NS_FAILED(
613 aWorkerPrivate->DispatchToMainThreadForMessaging(this)))
614 : NS_WARN_IF(NS_FAILED(aWorkerPrivate->DispatchToMainThread(this)))) {
615 ReleaseWorker();
616 RunBackOnWorkerThreadForCleanup(aWorkerPrivate);
617 return false;
620 return true;
623 NS_IMETHODIMP
624 WorkerProxyToMainThreadRunnable::Run() {
625 AssertIsOnMainThread();
626 RunOnMainThread(mWorkerRef->Private());
627 PostDispatchOnMainThread();
628 return NS_OK;
631 void WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread() {
632 class ReleaseRunnable final : public MainThreadWorkerControlRunnable {
633 RefPtr<WorkerProxyToMainThreadRunnable> mRunnable;
635 public:
636 ReleaseRunnable(WorkerPrivate* aWorkerPrivate,
637 WorkerProxyToMainThreadRunnable* aRunnable)
638 : MainThreadWorkerControlRunnable(aWorkerPrivate),
639 mRunnable(aRunnable) {
640 MOZ_ASSERT(aRunnable);
643 virtual nsresult Cancel() override {
644 Unused << WorkerRun(nullptr, mWorkerPrivate);
645 return NS_OK;
648 virtual bool WorkerRun(JSContext* aCx,
649 WorkerPrivate* aWorkerPrivate) override {
650 MOZ_ASSERT(aWorkerPrivate);
651 aWorkerPrivate->AssertIsOnWorkerThread();
653 if (mRunnable) {
654 mRunnable->RunBackOnWorkerThreadForCleanup(aWorkerPrivate);
656 // Let's release the worker thread.
657 mRunnable->ReleaseWorker();
658 mRunnable = nullptr;
661 return true;
664 private:
665 ~ReleaseRunnable() = default;
668 RefPtr<WorkerControlRunnable> runnable =
669 new ReleaseRunnable(mWorkerRef->Private(), this);
670 Unused << NS_WARN_IF(!runnable->Dispatch());
673 void WorkerProxyToMainThreadRunnable::ReleaseWorker() { mWorkerRef = nullptr; }
675 bool WorkerDebuggeeRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
676 if (mTarget == ParentThread) {
677 RefPtr<StrongWorkerRef> strongRef = StrongWorkerRef::Create(
678 aWorkerPrivate, "WorkerDebuggeeRunnable::mSender");
679 if (!strongRef) {
680 return false;
683 mSender = new ThreadSafeWorkerRef(strongRef);
686 return WorkerRunnable::PreDispatch(aWorkerPrivate);
689 } // namespace mozilla::dom