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 "MessagePort.h"
9 #include "MessageEvent.h"
10 #include "MessagePortChild.h"
11 #include "mozilla/dom/BlobBinding.h"
12 #include "mozilla/dom/Event.h"
13 #include "mozilla/dom/File.h"
14 #include "mozilla/dom/MessageChannel.h"
15 #include "mozilla/dom/MessageEventBinding.h"
16 #include "mozilla/dom/MessagePortBinding.h"
17 #include "mozilla/dom/MessagePortChild.h"
18 #include "mozilla/dom/PMessagePort.h"
19 #include "mozilla/dom/RootedDictionary.h"
20 #include "mozilla/dom/ScriptSettings.h"
21 #include "mozilla/dom/StructuredCloneTags.h"
22 #include "mozilla/dom/WorkerCommon.h"
23 #include "mozilla/dom/WorkerRef.h"
24 #include "mozilla/dom/WorkerScope.h"
25 #include "mozilla/ipc/BackgroundChild.h"
26 #include "mozilla/dom/RefMessageBodyService.h"
27 #include "mozilla/dom/SharedMessageBody.h"
28 #include "mozilla/ipc/PBackgroundChild.h"
29 #include "mozilla/ScopeExit.h"
30 #include "mozilla/Unused.h"
31 #include "nsContentUtils.h"
32 #include "nsPresContext.h"
38 namespace mozilla::dom
{
40 void UniqueMessagePortId::ForceClose() {
41 if (!mIdentifier
.neutered()) {
42 MessagePort::ForceClose(mIdentifier
);
43 mIdentifier
.neutered() = true;
47 class PostMessageRunnable final
: public CancelableRunnable
{
48 friend class MessagePort
;
51 PostMessageRunnable(MessagePort
* aPort
, SharedMessageBody
* aData
)
52 : CancelableRunnable("dom::PostMessageRunnable"),
61 NS_ASSERT_OWNINGTHREAD(Runnable
);
63 // The port can be cycle collected while this runnable is pending in
69 MOZ_ASSERT(mPort
->mPostMessageRunnable
== this);
73 // We must check if we were waiting for this message in order to shutdown
75 mPort
->UpdateMustKeepAlive();
77 mPort
->mPostMessageRunnable
= nullptr;
83 nsresult
Cancel() override
{
84 NS_ASSERT_OWNINGTHREAD(Runnable
);
92 void DispatchMessage() const {
93 NS_ASSERT_OWNINGTHREAD(Runnable
);
95 if (NS_FAILED(mPort
->CheckCurrentGlobalCorrectness())) {
99 nsCOMPtr
<nsIGlobalObject
> globalObject
= mPort
->GetParentObject();
102 if (!globalObject
|| !jsapi
.Init(globalObject
)) {
103 NS_WARNING("Failed to initialize AutoJSAPI object.");
107 JSContext
* cx
= jsapi
.cx();
109 IgnoredErrorResult rv
;
110 JS::Rooted
<JS::Value
> value(cx
);
112 mData
->Read(cx
, &value
, mPort
->mRefMessageBodyService
,
113 SharedMessageBody::ReadMethod::StealRefMessageBody
, rv
);
115 if (NS_WARN_IF(rv
.Failed())) {
116 JS_ClearPendingException(cx
);
117 mPort
->DispatchError();
122 nsCOMPtr
<mozilla::dom::EventTarget
> eventTarget
=
123 do_QueryInterface(mPort
->GetOwner());
124 RefPtr
<MessageEvent
> event
=
125 new MessageEvent(eventTarget
, nullptr, nullptr);
127 Sequence
<OwningNonNull
<MessagePort
>> ports
;
128 if (!mData
->TakeTransferredPortsAsSequence(ports
)) {
129 mPort
->DispatchError();
133 event
->InitMessageEvent(nullptr, u
"message"_ns
, CanBubble::eNo
,
134 Cancelable::eNo
, value
, u
""_ns
, u
""_ns
, nullptr,
136 event
->SetTrusted(true);
138 mPort
->DispatchEvent(*event
);
142 ~PostMessageRunnable() = default;
144 RefPtr
<MessagePort
> mPort
;
145 RefPtr
<SharedMessageBody
> mData
;
148 NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort
)
150 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort
,
151 DOMEventTargetHelper
)
152 if (tmp
->mPostMessageRunnable
) {
153 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPostMessageRunnable
->mPort
);
156 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagesForTheOtherPort
);
159 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
161 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort
,
162 DOMEventTargetHelper
)
163 if (tmp
->mPostMessageRunnable
) {
164 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPostMessageRunnable
->mPort
);
167 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnshippedEntangledPort
);
168 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
170 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessagePort
)
171 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
173 NS_IMPL_ADDREF_INHERITED(MessagePort
, DOMEventTargetHelper
)
174 NS_IMPL_RELEASE_INHERITED(MessagePort
, DOMEventTargetHelper
)
176 MessagePort::MessagePort(nsIGlobalObject
* aGlobal
, State aState
)
177 : DOMEventTargetHelper(aGlobal
),
178 mRefMessageBodyService(RefMessageBodyService::GetOrCreate()),
180 mMessageQueueEnabled(false),
182 mHasBeenTransferredOrClosed(false) {
185 mIdentifier
= MakeUnique
<MessagePortIdentifier
>();
186 mIdentifier
->neutered() = true;
187 mIdentifier
->sequenceId() = 0;
190 MessagePort::~MessagePort() {
194 mActor
->SetPort(nullptr);
197 MOZ_ASSERT(!mWorkerRef
);
201 already_AddRefed
<MessagePort
> MessagePort::Create(nsIGlobalObject
* aGlobal
,
203 const nsID
& aDestinationUUID
,
207 RefPtr
<MessagePort
> mp
=
208 new MessagePort(aGlobal
, eStateInitializingUnshippedEntangled
);
209 mp
->Initialize(aUUID
, aDestinationUUID
, 1 /* 0 is an invalid sequence ID */,
210 false /* Neutered */, aRv
);
215 already_AddRefed
<MessagePort
> MessagePort::Create(
216 nsIGlobalObject
* aGlobal
, UniqueMessagePortId
& aIdentifier
,
220 RefPtr
<MessagePort
> mp
= new MessagePort(aGlobal
, eStateEntangling
);
221 mp
->Initialize(aIdentifier
.uuid(), aIdentifier
.destinationUuid(),
222 aIdentifier
.sequenceId(), aIdentifier
.neutered(), aRv
);
223 aIdentifier
.neutered() = true;
227 void MessagePort::UnshippedEntangle(RefPtr
<MessagePort
>& aEntangledPort
) {
228 MOZ_DIAGNOSTIC_ASSERT(aEntangledPort
);
229 MOZ_DIAGNOSTIC_ASSERT(!mUnshippedEntangledPort
);
231 if (mState
== eStateInitializingUnshippedEntangled
) {
232 mUnshippedEntangledPort
= aEntangledPort
;
233 mState
= eStateUnshippedEntangled
;
235 MOZ_ASSERT_UNREACHABLE("Should not have been called.");
239 void MessagePort::Initialize(const nsID
& aUUID
, const nsID
& aDestinationUUID
,
240 uint32_t aSequenceID
, bool aNeutered
,
242 MOZ_ASSERT(mIdentifier
);
243 mIdentifier
->uuid() = aUUID
;
244 mIdentifier
->destinationUuid() = aDestinationUUID
;
245 mIdentifier
->sequenceId() = aSequenceID
;
248 // If this port is neutered we don't want to keep it alive artificially nor
249 // we want to add listeners or WorkerRefs.
250 mState
= eStateDisentangled
;
254 if (mState
== eStateEntangling
) {
255 if (!ConnectToPBackground()) {
256 aRv
.Throw(NS_ERROR_FAILURE
);
260 MOZ_ASSERT(mState
== eStateInitializingUnshippedEntangled
);
263 // The port has to keep itself alive until it's entangled.
264 UpdateMustKeepAlive();
266 if (WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate()) {
267 RefPtr
<MessagePort
> self
= this;
269 // When the callback is executed, we cannot process messages anymore because
270 // we cannot dispatch new runnables. Let's force a Close().
271 RefPtr
<StrongWorkerRef
> strongWorkerRef
= StrongWorkerRef::Create(
272 workerPrivate
, "MessagePort", [self
]() { self
->CloseForced(); });
273 if (NS_WARN_IF(!strongWorkerRef
)) {
274 // The worker is shutting down.
276 aRv
.Throw(NS_ERROR_FAILURE
);
280 MOZ_ASSERT(!mWorkerRef
);
281 mWorkerRef
= std::move(strongWorkerRef
);
285 JSObject
* MessagePort::WrapObject(JSContext
* aCx
,
286 JS::Handle
<JSObject
*> aGivenProto
) {
287 return MessagePort_Binding::Wrap(aCx
, this, aGivenProto
);
290 void MessagePort::PostMessage(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
291 const Sequence
<JSObject
*>& aTransferable
,
293 // We *must* clone the data here, or the JS::Value could be modified
296 // Here we want to check if the transerable object list contains
298 for (uint32_t i
= 0; i
< aTransferable
.Length(); ++i
) {
299 JS::Rooted
<JSObject
*> object(aCx
, aTransferable
[i
]);
304 MessagePort
* port
= nullptr;
305 nsresult rv
= UNWRAP_OBJECT(MessagePort
, &object
, port
);
306 if (NS_SUCCEEDED(rv
) && port
== this) {
307 aRv
.Throw(NS_ERROR_DOM_DATA_CLONE_ERR
);
312 JS::Rooted
<JS::Value
> transferable(aCx
, JS::UndefinedValue());
314 aRv
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransferable
,
316 if (NS_WARN_IF(aRv
.Failed())) {
320 Maybe
<nsID
> agentClusterId
;
321 nsCOMPtr
<nsIGlobalObject
> global
= GetOwnerGlobal();
323 agentClusterId
= global
->GetAgentClusterId();
326 RefPtr
<SharedMessageBody
> data
= new SharedMessageBody(
327 StructuredCloneHolder::TransferringSupported
, agentClusterId
);
329 data
->Write(aCx
, aMessage
, transferable
, mIdentifier
->uuid(),
330 mRefMessageBodyService
, aRv
);
332 if (NS_WARN_IF(aRv
.Failed())) {
336 // This message has to be ignored.
337 if (mState
> eStateEntangled
) {
341 if (mState
== eStateInitializingUnshippedEntangled
) {
342 MOZ_ASSERT_UNREACHABLE(
343 "Should be eStateUnshippedEntangled or eStateDisentangled by now.");
347 // If we are unshipped we are connected to the other port on the same thread.
348 if (mState
== eStateUnshippedEntangled
) {
349 MOZ_DIAGNOSTIC_ASSERT(mUnshippedEntangledPort
);
350 mUnshippedEntangledPort
->mMessages
.AppendElement(data
);
351 mUnshippedEntangledPort
->Dispatch();
355 // Not entangled yet, but already closed/disentangled.
356 if (mState
== eStateEntanglingForDisentangle
||
357 mState
== eStateEntanglingForClose
) {
361 RemoveDocFromBFCache();
363 // Not entangled yet.
364 if (mState
== eStateEntangling
) {
365 mMessagesForTheOtherPort
.AppendElement(data
);
370 MOZ_ASSERT(mMessagesForTheOtherPort
.IsEmpty());
372 AutoTArray
<RefPtr
<SharedMessageBody
>, 1> array
;
373 array
.AppendElement(data
);
375 AutoTArray
<MessageData
, 1> messages
;
376 // note: `messages` will borrow the underlying buffer, but this is okay
377 // because reverse destruction order means `messages` will be destroyed prior
378 // to `array`/`data`.
379 SharedMessageBody::FromSharedToMessagesChild(mActor
->Manager(), array
,
381 mActor
->SendPostMessages(messages
);
384 void MessagePort::PostMessage(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
385 const StructuredSerializeOptions
& aOptions
,
387 PostMessage(aCx
, aMessage
, aOptions
.mTransfer
, aRv
);
390 void MessagePort::Start() {
391 if (mMessageQueueEnabled
) {
395 mMessageQueueEnabled
= true;
399 void MessagePort::Dispatch() {
400 if (!mMessageQueueEnabled
|| mMessages
.IsEmpty() || mPostMessageRunnable
) {
405 case eStateInitializingUnshippedEntangled
:
406 MOZ_ASSERT_UNREACHABLE(
407 "Should be eStateUnshippedEntangled or eStateDisentangled by now.");
410 case eStateUnshippedEntangled
:
411 // Everything is fine here. We have messages because the other
412 // port populates our queue directly.
415 case eStateEntangling
:
416 // Everything is fine here as well. We have messages because the other
417 // port populated our queue directly when we were in the
418 // eStateUnshippedEntangled state.
421 case eStateEntanglingForDisentangle
:
422 // Here we don't want to ship messages because these messages must be
423 // delivered by the cloned version of this one. They will be sent in the
424 // SendDisentangle().
427 case eStateEntanglingForClose
:
428 // We still want to deliver messages if we are closing. These messages
429 // are here from the previous eStateUnshippedEntangled state.
432 case eStateEntangled
:
433 // This port is up and running.
436 case eStateDisentangling
:
437 // If we are in the process to disentangle the port, we cannot dispatch
438 // messages. They will be sent to the cloned version of this port via
439 // SendDisentangle();
442 case eStateDisentangled
:
443 MOZ_CRASH("This cannot happen.");
444 // It cannot happen because Disentangle should take off all the pending
448 case eStateDisentangledForClose
:
449 // If we are here is because the port has been closed. We can still
450 // process the pending messages.
454 RefPtr
<SharedMessageBody
> data
= mMessages
.ElementAt(0);
455 mMessages
.RemoveElementAt(0);
457 mPostMessageRunnable
= new PostMessageRunnable(this, data
);
458 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(mPostMessageRunnable
));
461 void MessagePort::Close() {
462 mHasBeenTransferredOrClosed
= true;
463 CloseInternal(true /* aSoftly */);
466 void MessagePort::CloseForced() { CloseInternal(false /* aSoftly */); }
468 void MessagePort::CloseInternal(bool aSoftly
) {
469 // If we have some messages to send but we don't want a 'soft' close, we have
470 // to flush them now.
475 // Let's inform the RefMessageBodyService that any our shared messages are
477 mRefMessageBodyService
->ForgetPort(mIdentifier
->uuid());
479 if (mState
== eStateInitializingUnshippedEntangled
) {
480 // We can end up here if we failed to create our WorkerRef. Our Create
481 // method will end up returning an error and MessageChannel will not bother
482 // creating our counterpart port or calling UnshippedEntangle (and we
484 mState
= eStateDisentangledForClose
;
486 UpdateMustKeepAlive();
490 if (mState
== eStateUnshippedEntangled
) {
491 MOZ_DIAGNOSTIC_ASSERT(mUnshippedEntangledPort
);
493 // This avoids loops.
494 RefPtr
<MessagePort
> port
= std::move(mUnshippedEntangledPort
);
496 mState
= eStateDisentangledForClose
;
497 port
->CloseInternal(aSoftly
);
499 UpdateMustKeepAlive();
503 // Not entangled yet, we have to wait.
504 if (mState
== eStateEntangling
) {
505 mState
= eStateEntanglingForClose
;
509 // Not entangled but already cloned or closed
510 if (mState
== eStateEntanglingForDisentangle
||
511 mState
== eStateEntanglingForClose
) {
515 // Maybe we were already closing the port but softly. In this case we call
516 // UpdateMustKeepAlive() to consider the empty pending message queue.
517 if (mState
== eStateDisentangledForClose
&& !aSoftly
) {
518 UpdateMustKeepAlive();
522 if (mState
> eStateEntangled
) {
526 // We don't care about stopping the sending of messages because from now all
527 // the incoming messages will be ignored.
528 mState
= eStateDisentangledForClose
;
533 mActor
->SetPort(nullptr);
536 UpdateMustKeepAlive();
539 EventHandlerNonNull
* MessagePort::GetOnmessage() {
540 return GetEventHandler(nsGkAtoms::onmessage
);
543 void MessagePort::SetOnmessage(EventHandlerNonNull
* aCallback
) {
544 SetEventHandler(nsGkAtoms::onmessage
, aCallback
);
546 // When using onmessage, the call to start() is implied.
550 // This method is called when the PMessagePortChild actor is entangled to
551 // another actor. It receives a list of messages to be dispatch. It can be that
552 // we were waiting for this entangling step in order to disentangle the port or
554 void MessagePort::Entangled(nsTArray
<MessageData
>& aMessages
) {
555 MOZ_ASSERT(mState
== eStateEntangling
||
556 mState
== eStateEntanglingForDisentangle
||
557 mState
== eStateEntanglingForClose
);
559 State oldState
= mState
;
560 mState
= eStateEntangled
;
562 // If we have pending messages, these have to be sent.
563 if (!mMessagesForTheOtherPort
.IsEmpty()) {
565 nsTArray
<MessageData
> messages
;
566 SharedMessageBody::FromSharedToMessagesChild(
567 mActor
->Manager(), mMessagesForTheOtherPort
, messages
);
568 mActor
->SendPostMessages(messages
);
570 // Because `messages` borrow the underlying JSStructuredCloneData buffers,
571 // only clear after `messages` have gone out of scope.
572 mMessagesForTheOtherPort
.Clear();
575 // We must convert the messages into SharedMessageBodys to avoid leaks.
576 FallibleTArray
<RefPtr
<SharedMessageBody
>> data
;
578 !SharedMessageBody::FromMessagesToSharedChild(aMessages
, data
))) {
583 // If the next step is to close the port, we do it ignoring the received
585 if (oldState
== eStateEntanglingForClose
) {
590 mMessages
.AppendElements(data
);
592 // We were waiting for the entangling callback in order to disentangle this
593 // port immediately after.
594 if (oldState
== eStateEntanglingForDisentangle
) {
595 StartDisentangling();
602 void MessagePort::StartDisentangling() {
604 MOZ_ASSERT(mState
== eStateEntangled
);
606 mState
= eStateDisentangling
;
608 // Sending this message we communicate to the parent actor that we don't want
609 // to receive any new messages. It is possible that a message has been
610 // already sent but not received yet. So we have to collect all of them and
611 // we send them in the SendDispatch() request.
612 mActor
->SendStopSendingData();
615 void MessagePort::MessagesReceived(nsTArray
<MessageData
>& aMessages
) {
616 MOZ_ASSERT(mState
== eStateEntangled
|| mState
== eStateDisentangling
||
617 // This last step can happen only if Close() has been called
618 // manually. At this point SendClose() is sent but we can still
619 // receive something until the Closing request is processed.
620 mState
== eStateDisentangledForClose
);
621 MOZ_ASSERT(mMessagesForTheOtherPort
.IsEmpty());
623 RemoveDocFromBFCache();
625 FallibleTArray
<RefPtr
<SharedMessageBody
>> data
;
627 !SharedMessageBody::FromMessagesToSharedChild(aMessages
, data
))) {
632 mMessages
.AppendElements(data
);
634 if (mState
== eStateEntangled
) {
639 void MessagePort::StopSendingDataConfirmed() {
640 MOZ_ASSERT(mState
== eStateDisentangling
);
646 void MessagePort::Disentangle() {
647 MOZ_ASSERT(mState
== eStateDisentangling
);
650 mState
= eStateDisentangled
;
653 nsTArray
<MessageData
> messages
;
654 SharedMessageBody::FromSharedToMessagesChild(mActor
->Manager(), mMessages
,
656 mActor
->SendDisentangle(messages
);
659 // Let's inform the RefMessageBodyService that any our shared messages are
661 mRefMessageBodyService
->ForgetPort(mIdentifier
->uuid());
663 // Only clear mMessages after the MessageData instances have gone out of scope
664 // because they borrow mMessages' underlying JSStructuredCloneDatas.
667 mActor
->SetPort(nullptr);
670 UpdateMustKeepAlive();
673 void MessagePort::CloneAndDisentangle(UniqueMessagePortId
& aIdentifier
) {
674 MOZ_ASSERT(mIdentifier
);
675 MOZ_ASSERT(!mHasBeenTransferredOrClosed
);
677 mHasBeenTransferredOrClosed
= true;
679 // We can clone a port that has already been transfered. In this case, on the
680 // otherside will have a neutered port. Here we set neutered to true so that
681 // we are safe in case a early return.
682 aIdentifier
.neutered() = true;
684 if (mState
> eStateEntangled
) {
688 // We already have a 'next step'. We have to consider this port as already
689 // cloned/closed/disentangled.
690 if (mState
== eStateEntanglingForDisentangle
||
691 mState
== eStateEntanglingForClose
) {
695 aIdentifier
.uuid() = mIdentifier
->uuid();
696 aIdentifier
.destinationUuid() = mIdentifier
->destinationUuid();
697 aIdentifier
.sequenceId() = mIdentifier
->sequenceId() + 1;
698 aIdentifier
.neutered() = false;
700 // We have to entangle first.
701 if (mState
== eStateUnshippedEntangled
) {
702 MOZ_ASSERT(mUnshippedEntangledPort
);
703 MOZ_ASSERT(mMessagesForTheOtherPort
.IsEmpty());
705 RefPtr
<MessagePort
> port
= std::move(mUnshippedEntangledPort
);
707 // Disconnect the entangled port and connect it to PBackground.
708 if (!port
->ConnectToPBackground()) {
709 // We are probably shutting down. We cannot proceed.
710 mState
= eStateDisentangled
;
711 UpdateMustKeepAlive();
715 // In this case, we don't need to be connected to the PBackground service.
716 if (mMessages
.IsEmpty()) {
717 aIdentifier
.sequenceId() = mIdentifier
->sequenceId();
719 mState
= eStateDisentangled
;
720 UpdateMustKeepAlive();
724 // Register this component to PBackground.
725 if (!ConnectToPBackground()) {
726 // We are probably shutting down. We cannot proceed.
730 mState
= eStateEntanglingForDisentangle
;
734 // Not entangled yet, we have to wait.
735 if (mState
== eStateEntangling
) {
736 mState
= eStateEntanglingForDisentangle
;
740 MOZ_ASSERT(mState
== eStateEntangled
);
741 StartDisentangling();
744 void MessagePort::Closed() {
745 if (mState
>= eStateDisentangled
) {
749 mState
= eStateDisentangledForClose
;
752 mActor
->SetPort(nullptr);
756 UpdateMustKeepAlive();
759 bool MessagePort::ConnectToPBackground() {
760 RefPtr
<MessagePort
> self
= this;
761 auto raii
= MakeScopeExit([self
] {
762 self
->mState
= eStateDisentangled
;
763 self
->UpdateMustKeepAlive();
766 mozilla::ipc::PBackgroundChild
* actorChild
=
767 mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
768 if (NS_WARN_IF(!actorChild
)) {
772 PMessagePortChild
* actor
= actorChild
->SendPMessagePortConstructor(
773 mIdentifier
->uuid(), mIdentifier
->destinationUuid(),
774 mIdentifier
->sequenceId());
775 if (NS_WARN_IF(!actor
)) {
779 mActor
= static_cast<MessagePortChild
*>(actor
);
782 mActor
->SetPort(this);
783 mState
= eStateEntangling
;
789 void MessagePort::UpdateMustKeepAlive() {
790 if (mState
>= eStateDisentangled
&& mMessages
.IsEmpty() && mIsKeptAlive
) {
791 mIsKeptAlive
= false;
793 // The DTOR of this WorkerRef will release the worker for us.
794 mWorkerRef
= nullptr;
800 if (mState
< eStateDisentangled
&& !mIsKeptAlive
) {
806 void MessagePort::DisconnectFromOwner() {
808 DOMEventTargetHelper::DisconnectFromOwner();
811 void MessagePort::RemoveDocFromBFCache() {
812 if (!NS_IsMainThread()) {
816 if (nsPIDOMWindowInner
* window
= GetOwner()) {
817 window
->RemoveFromBFCacheSync();
822 void MessagePort::ForceClose(const MessagePortIdentifier
& aIdentifier
) {
823 mozilla::ipc::PBackgroundChild
* actorChild
=
824 mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
825 if (NS_WARN_IF(!actorChild
)) {
826 MOZ_CRASH("Failed to create a PBackgroundChild actor!");
829 Unused
<< actorChild
->SendMessagePortForceClose(aIdentifier
.uuid(),
830 aIdentifier
.destinationUuid(),
831 aIdentifier
.sequenceId());
834 void MessagePort::DispatchError() {
835 nsCOMPtr
<nsIGlobalObject
> globalObject
= GetParentObject();
838 if (!globalObject
|| !jsapi
.Init(globalObject
)) {
839 NS_WARNING("Failed to initialize AutoJSAPI object.");
843 RootedDictionary
<MessageEventInit
> init(jsapi
.cx());
844 init
.mBubbles
= false;
845 init
.mCancelable
= false;
847 RefPtr
<Event
> event
=
848 MessageEvent::Constructor(this, u
"messageerror"_ns
, init
);
849 event
->SetTrusted(true);
851 DispatchEvent(*event
);
854 } // namespace mozilla::dom