--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -109,18 +109,17 @@ PostMessageEvent::Run()
do_QueryInterface(static_cast<nsPIDOMWindow*>(targetWindow.get()));
nsRefPtr<MessageEvent> event =
new MessageEvent(eventTarget, nullptr, nullptr);
event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */,
false /*cancelable */, messageData, mCallerOrigin,
EmptyString(), mSource);
- nsTArray<nsRefPtr<MessagePortBase>> ports;
- TakeTransferredPorts(ports);
+ nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
ports));
// We can't simply call dispatchEvent on the window because doing so ends
// up flipping the trusted bit on the event, and we don't want that to
// happen because then untrusted content can call postMessage on a chrome
// window if it can get a reference to it.
--- a/dom/base/PostMessageEvent.h
+++ b/dom/base/PostMessageEvent.h
@@ -15,19 +15,16 @@
class nsGlobalWindow;
class nsIPrincipal;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
-class MessagePortBase;
-class MessagePortIdentifier;
-
/**
* Class used to represent events generated by calls to Window.postMessage,
* which asynchronously creates and dispatches events.
*/
class PostMessageEvent final : public nsRunnable
, public StructuredCloneHelper
{
public:
--- a/dom/base/StructuredCloneHelper.cpp
+++ b/dom/base/StructuredCloneHelper.cpp
@@ -1067,26 +1067,24 @@ StructuredCloneHelper::WriteTransferCall
void** aContent,
uint64_t* aExtraData)
{
if (!mSupportsTransferring) {
return false;
}
{
- MessagePortBase* port = nullptr;
+ MessagePort* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
if (NS_SUCCEEDED(rv)) {
// We use aExtraData to store the index of this new port identifier.
*aExtraData = mPortIdentifiers.Length();
MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement();
- if (!port->CloneAndDisentangle(*identifier)) {
- return false;
- }
+ port->CloneAndDisentangle(*identifier);
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
*aOwnership = JS::SCTAG_TMO_CUSTOM;
*aContent = nullptr;
return true;
}
}
--- a/dom/base/StructuredCloneHelper.h
+++ b/dom/base/StructuredCloneHelper.h
@@ -2,16 +2,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_StructuredCloneHelper_h
#define mozilla_dom_StructuredCloneHelper_h
#include "js/StructuredClone.h"
+#include "mozilla/Move.h"
#include "nsAutoPtr.h"
#include "nsISupports.h"
#include "nsTArray.h"
#ifdef DEBUG
#include "nsIThread.h"
#endif
@@ -106,17 +107,17 @@ protected:
nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
#ifdef DEBUG
bool mShutdownCalled;
#endif
};
class BlobImpl;
-class MessagePortBase;
+class MessagePort;
class MessagePortIdentifier;
class StructuredCloneHelper : public StructuredCloneHelperInternal
{
public:
enum CloningSupport
{
CloningSupported,
@@ -186,21 +187,20 @@ public:
nsISupports* ParentDuringRead() const
{
return mParent;
}
// This must be called if the transferring has ports generated by Read().
// MessagePorts are not thread-safe and they must be retrieved in the thread
// where they are created.
- void TakeTransferredPorts(nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
+ nsTArray<nsRefPtr<MessagePort>>&& TakeTransferredPorts()
{
MOZ_ASSERT(mSupportsTransferring);
- MOZ_ASSERT(aPorts.IsEmpty());
- aPorts.SwapElements(mTransferredPorts);
+ return Move(mTransferredPorts);
}
nsTArray<MessagePortIdentifier>& PortIdentifiers()
{
MOZ_ASSERT(mSupportsTransferring);
return mPortIdentifiers;
}
@@ -286,17 +286,17 @@ protected:
nsTArray<nsRefPtr<layers::Image>> mClonedImages;
// This raw pointer is set and unset into the ::Read(). It's always null
// outside that method. For this reason it's a raw pointer.
nsISupports* MOZ_NON_OWNING_REF mParent;
// This array contains the ports once we've finished the reading. It's
// generated from the mPortIdentifiers array.
- nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts;
+ nsTArray<nsRefPtr<MessagePort>> mTransferredPorts;
// This array contains the identifiers of the MessagePorts. Based on these we
// are able to reconnect the new transferred ports with the other
// MessageChannel ports.
nsTArray<MessagePortIdentifier> mPortIdentifiers;
#ifdef DEBUG
nsCOMPtr<nsIThread> mCreationThread;
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -734,21 +734,16 @@ DOMInterfaces = {
'MediaStreamTrack': {
'concrete': False
},
'MediaRecorder': {
'headerFile': 'MediaRecorder.h',
},
-'MessagePort': {
- 'nativeType': 'mozilla::dom::MessagePortBase',
- 'headerFile': 'mozilla/dom/MessagePort.h',
-},
-
'MimeType': {
'headerFile' : 'nsMimeTypeArray.h',
'nativeType': 'nsMimeType',
},
'MimeTypeArray': {
'nativeType': 'nsMimeTypeArray',
},
--- a/dom/events/MessageEvent.cpp
+++ b/dom/events/MessageEvent.cpp
@@ -162,17 +162,17 @@ MessageEvent::Constructor(EventTarget* a
} else {
event->mPortSource = aParam.mSource.Value().GetAsMessagePort();
}
MOZ_ASSERT(event->mWindowSource || event->mPortSource);
}
if (aParam.mPorts.WasPassed() && !aParam.mPorts.Value().IsNull()) {
- nsTArray<nsRefPtr<MessagePortBase>> ports;
+ nsTArray<nsRefPtr<MessagePort>> ports;
for (uint32_t i = 0, len = aParam.mPorts.Value().Value().Length(); i < len; ++i) {
ports.AppendElement(aParam.mPorts.Value().Value()[i].get());
}
event->mPorts = new MessagePortList(static_cast<Event*>(event), ports);
}
return event.forget();
--- a/dom/events/MessageEvent.h
+++ b/dom/events/MessageEvent.h
@@ -12,17 +12,16 @@
#include "nsIDOMMessageEvent.h"
#include "mozilla/dom/MessagePortList.h"
namespace mozilla {
namespace dom {
struct MessageEventInit;
class MessagePort;
-class MessagePortBase;
class MessagePortList;
class OwningWindowProxyOrMessagePortOrClient;
namespace workers {
class ServiceWorkerClient;
} // namespace workers
@@ -89,17 +88,17 @@ public:
protected:
~MessageEvent();
private:
JS::Heap<JS::Value> mData;
nsString mOrigin;
nsString mLastEventId;
nsCOMPtr<nsIDOMWindow> mWindowSource;
- nsRefPtr<MessagePortBase> mPortSource;
+ nsRefPtr<MessagePort> mPortSource;
nsRefPtr<workers::ServiceWorkerClient> mClientSource;
nsRefPtr<MessagePortList> mPorts;
};
} // namespace dom
} // namespace mozilla
already_AddRefed<mozilla::dom::MessageEvent>
--- a/dom/messagechannel/MessageChannel.cpp
+++ b/dom/messagechannel/MessageChannel.cpp
@@ -44,37 +44,42 @@ MessageChannel::WrapObject(JSContext* aC
return MessageChannelBinding::Wrap(aCx, this, aGivenProto);
}
/* static */ already_AddRefed<MessageChannel>
MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
// window can be null in workers.
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+ return Constructor(window, aRv);
+}
+/* static */ already_AddRefed<MessageChannel>
+MessageChannel::Constructor(nsPIDOMWindow* aWindow, ErrorResult& aRv)
+{
nsID portUUID1;
aRv = nsContentUtils::GenerateUUIDInPlace(portUUID1);
if (aRv.Failed()) {
return nullptr;
}
nsID portUUID2;
aRv = nsContentUtils::GenerateUUIDInPlace(portUUID2);
if (aRv.Failed()) {
return nullptr;
}
- nsRefPtr<MessageChannel> channel = new MessageChannel(window);
+ nsRefPtr<MessageChannel> channel = new MessageChannel(aWindow);
- channel->mPort1 = MessagePort::Create(window, portUUID1, portUUID2, aRv);
+ channel->mPort1 = MessagePort::Create(aWindow, portUUID1, portUUID2, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
- channel->mPort2 = MessagePort::Create(window, portUUID2, portUUID1, aRv);
+ channel->mPort2 = MessagePort::Create(aWindow, portUUID2, portUUID1, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
channel->mPort1->UnshippedEntangle(channel->mPort2);
channel->mPort2->UnshippedEntangle(channel->mPort1);
return channel.forget();
--- a/dom/messagechannel/MessageChannel.h
+++ b/dom/messagechannel/MessageChannel.h
@@ -35,16 +35,19 @@ public:
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<MessageChannel>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+ static already_AddRefed<MessageChannel>
+ Constructor(nsPIDOMWindow* aWindow, ErrorResult& aRv);
+
MessagePort*
Port1() const
{
return mPort1;
}
MessagePort*
Port2() const
--- a/dom/messagechannel/MessagePort.cpp
+++ b/dom/messagechannel/MessagePort.cpp
@@ -135,18 +135,17 @@ public:
event->InitMessageEvent(NS_LITERAL_STRING("message"),
false /* non-bubbling */,
false /* cancelable */, value, EmptyString(),
EmptyString(), nullptr);
event->SetTrusted(true);
event->SetSource(mPort);
- nsTArray<nsRefPtr<MessagePortBase>> ports;
- mData->TakeTransferredPorts(ports);
+ nsTArray<nsRefPtr<MessagePort>> ports = mData->TakeTransferredPorts();
nsRefPtr<MessagePortList> portList =
new MessagePortList(static_cast<dom::Event*>(event.get()),
ports);
event->SetPorts(portList);
bool dummy;
mPort->DispatchEvent(static_cast<dom::Event*>(event.get()), &dummy);
@@ -166,54 +165,45 @@ private:
{}
nsRefPtr<MessagePort> mPort;
nsRefPtr<SharedMessagePortMessage> mData;
};
NS_IMPL_ISUPPORTS(PostMessageRunnable, nsICancelableRunnable, nsIRunnable)
-MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow)
- : DOMEventTargetHelper(aWindow)
-{
-}
-
-MessagePortBase::MessagePortBase()
-{
-}
-
NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
- MessagePortBase)
+ DOMEventTargetHelper)
if (tmp->mDispatchRunnable) {
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessages);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagesForTheOtherPort);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mUnshippedEntangledPort);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
- MessagePortBase)
+ DOMEventTargetHelper)
if (tmp->mDispatchRunnable) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnshippedEntangledPort);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
-NS_INTERFACE_MAP_END_INHERITING(MessagePortBase)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-NS_IMPL_ADDREF_INHERITED(MessagePort, MessagePortBase)
-NS_IMPL_RELEASE_INHERITED(MessagePort, MessagePortBase)
+NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper)
namespace {
class MessagePortFeature final : public workers::WorkerFeature
{
MessagePort* mPort;
public:
@@ -282,17 +272,17 @@ private:
const MessagePortIdentifier mIdentifier;
};
NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback)
} // namespace
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
- : MessagePortBase(aWindow)
+ : DOMEventTargetHelper(aWindow)
, mInnerID(0)
, mMessageQueueEnabled(false)
, mIsKeptAlive(false)
{
mIdentifier = new MessagePortIdentifier();
mIdentifier->neutered() = true;
mIdentifier->sequenceId() = 0;
}
@@ -359,38 +349,38 @@ MessagePort::Initialize(const nsID& aUUI
ConnectToPBackground();
} else {
MOZ_ASSERT(mState == eStateUnshippedEntangled);
}
// The port has to keep itself alive until it's entangled.
UpdateMustKeepAlive();
- if (NS_IsMainThread()) {
- MOZ_ASSERT(GetOwner());
- MOZ_ASSERT(GetOwner()->IsInnerWindow());
- mInnerID = GetOwner()->WindowID();
-
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->AddObserver(this, "inner-window-destroyed", false);
- }
- } else {
+ if (!NS_IsMainThread()) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
MOZ_ASSERT(!mWorkerFeature);
nsAutoPtr<WorkerFeature> feature(new MessagePortFeature(this));
JSContext* cx = workerPrivate->GetJSContext();
if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
mWorkerFeature = Move(feature);
+ } else if (GetOwner()) {
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(GetOwner()->IsInnerWindow());
+ mInnerID = GetOwner()->WindowID();
+
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ if (obs) {
+ obs->AddObserver(this, "inner-window-destroyed", false);
+ }
}
}
JSObject*
MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return MessagePortBinding::Wrap(aCx, this, aGivenProto);
}
@@ -409,17 +399,17 @@ MessagePort::PostMessage(JSContext* aCx,
// Here we want to check if the transerable object list contains
// this port. No other checks are done.
for (const JS::Value& value : realTransferable) {
if (!value.isObject()) {
continue;
}
- MessagePortBase* port = nullptr;
+ MessagePort* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, &value.toObject(), port);
if (NS_FAILED(rv)) {
continue;
}
if (port == this) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
@@ -515,37 +505,32 @@ MessagePort::Dispatch()
mDispatchRunnable = new DispatchEventRunnable(this);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(mDispatchRunnable)));
}
void
MessagePort::Close()
{
- // Not entangled yet, but already closed.
- if (mNextStep != eNextStepNone) {
- return;
- }
-
if (mState == eStateUnshippedEntangled) {
MOZ_ASSERT(mUnshippedEntangledPort);
// This avoids loops.
nsRefPtr<MessagePort> port = Move(mUnshippedEntangledPort);
MOZ_ASSERT(mUnshippedEntangledPort == nullptr);
mState = eStateDisentangled;
port->Close();
UpdateMustKeepAlive();
return;
}
// Not entangled yet, we have to wait.
- if (mState < eStateEntangling) {
+ if (mState == eStateEntangling) {
mNextStep = eNextStepClose;
return;
}
if (mState > eStateEntangled) {
return;
}
@@ -694,34 +679,34 @@ MessagePort::Disentangle()
mActor->SendDisentangle(messages);
mActor->SetPort(nullptr);
mActor = nullptr;
UpdateMustKeepAlive();
}
-bool
+void
MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
{
MOZ_ASSERT(mIdentifier);
// We can clone a port that has already been transfered. In this case, on the
// otherside will have a neutered port. Here we set neutered to true so that
// we are safe in case a early return.
aIdentifier.neutered() = true;
if (mState > eStateEntangled) {
- return true;
+ return;
}
// We already have a 'next step'. We have to consider this port as already
// cloned/closed/disentangled.
if (mNextStep != eNextStepNone) {
- return true;
+ return;
}
aIdentifier.uuid() = mIdentifier->uuid();
aIdentifier.destinationUuid() = mIdentifier->destinationUuid();
aIdentifier.sequenceId() = mIdentifier->sequenceId() + 1;
aIdentifier.neutered() = false;
// We have to entangle first.
@@ -734,34 +719,33 @@ MessagePort::CloneAndDisentangle(Message
mUnshippedEntangledPort = nullptr;
// In this case, we don't need to be connected to the PBackground service.
if (mMessages.IsEmpty()) {
aIdentifier.sequenceId() = mIdentifier->sequenceId();
mState = eStateDisentangled;
UpdateMustKeepAlive();
- return true;
+ return;
}
// Register this component to PBackground.
ConnectToPBackground();
mNextStep = eNextStepDisentangle;
- return true;
+ return;
}
// Not entangled yet, we have to wait.
if (mState < eStateEntangled) {
mNextStep = eNextStepDisentangle;
- return true;
+ return;
}
StartDisentangling();
- return true;
}
void
MessagePort::Closed()
{
if (mState == eStateDisentangled) {
return;
}
--- a/dom/messagechannel/MessagePort.h
+++ b/dom/messagechannel/MessagePort.h
@@ -26,95 +26,61 @@ class MessagePortChild;
class MessagePortIdentifier;
class MessagePortMessage;
class SharedMessagePortMessage;
namespace workers {
class WorkerFeature;
} // namespace workers
-class MessagePortBase : public DOMEventTargetHelper
-{
-protected:
- explicit MessagePortBase(nsPIDOMWindow* aWindow);
- MessagePortBase();
-
-public:
-
- virtual void
- PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
- const Optional<Sequence<JS::Value>>& aTransferable,
- ErrorResult& aRv) = 0;
-
- virtual void
- Start() = 0;
-
- virtual void
- Close() = 0;
-
- // The 'message' event handler has to call |Start()| method, so we
- // cannot use IMPL_EVENT_HANDLER macro here.
- virtual EventHandlerNonNull*
- GetOnmessage() = 0;
-
- virtual void
- SetOnmessage(EventHandlerNonNull* aCallback) = 0;
-
- // Duplicate this message port. This method is used by the Structured Clone
- // Algorithm and populates a MessagePortIdentifier object with the information
- // useful to create new MessagePort.
- virtual bool
- CloneAndDisentangle(MessagePortIdentifier& aIdentifier) = 0;
-};
-
-class MessagePort final : public MessagePortBase
+class MessagePort final : public DOMEventTargetHelper
, public nsIIPCBackgroundChildCreateCallback
, public nsIObserver
{
friend class DispatchEventRunnable;
public:
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
NS_DECL_NSIOBSERVER
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
- MessagePortBase)
+ DOMEventTargetHelper)
static already_AddRefed<MessagePort>
Create(nsPIDOMWindow* aWindow, const nsID& aUUID,
const nsID& aDestinationUUID, ErrorResult& aRv);
static already_AddRefed<MessagePort>
Create(nsPIDOMWindow* aWindow, const MessagePortIdentifier& aIdentifier,
ErrorResult& aRv);
static void
ForceClose(const MessagePortIdentifier& aIdentifier);
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
- virtual void
+ void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
- ErrorResult& aRv) override;
+ ErrorResult& aRv);
- virtual void Start() override;
+ void Start();
- virtual void Close() override;
+ void Close();
- virtual EventHandlerNonNull* GetOnmessage() override;
+ EventHandlerNonNull* GetOnmessage();
- virtual void SetOnmessage(EventHandlerNonNull* aCallback) override;
+ void SetOnmessage(EventHandlerNonNull* aCallback);
// Non WebIDL methods
void UnshippedEntangle(MessagePort* aEntangledPort);
- virtual bool CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
+ void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);
// These methods are useful for MessagePortChild
void Entangled(nsTArray<MessagePortMessage>& aMessages);
void MessagesReceived(nsTArray<MessagePortMessage>& aMessages);
void StopSendingDataConfirmed();
void Closed();
--- a/dom/messagechannel/MessagePortList.h
+++ b/dom/messagechannel/MessagePortList.h
@@ -24,17 +24,17 @@ class MessagePortList final : public nsI
~MessagePortList() {}
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MessagePortList)
public:
MessagePortList(nsISupports* aOwner,
- const nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
+ const nsTArray<nsRefPtr<MessagePort>>& aPorts)
: mOwner(aOwner)
, mPorts(aPorts)
{
}
nsISupports*
GetParentObject() const
{
@@ -45,34 +45,34 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
uint32_t
Length() const
{
return mPorts.Length();
}
- MessagePortBase*
+ MessagePort*
Item(uint32_t aIndex)
{
return mPorts.SafeElementAt(aIndex);
}
- MessagePortBase*
+ MessagePort*
IndexedGetter(uint32_t aIndex, bool &aFound)
{
aFound = aIndex < mPorts.Length();
if (!aFound) {
return nullptr;
}
return mPorts[aIndex];
}
public:
nsCOMPtr<nsISupports> mOwner;
- nsTArray<nsRefPtr<MessagePortBase>> mPorts;
+ nsTArray<nsRefPtr<MessagePort>> mPorts;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MessagePortList_h
deleted file mode 100644
--- a/dom/workers/MessagePort.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MessagePort.h"
-
-#include "mozilla/EventDispatcher.h"
-#include "mozilla/dom/MessagePortBinding.h"
-#include "mozilla/dom/ScriptSettings.h"
-#include "nsIDOMEvent.h"
-
-#include "SharedWorker.h"
-#include "WorkerPrivate.h"
-#include "WorkerRunnable.h"
-
-using mozilla::dom::EventHandlerNonNull;
-using mozilla::dom::MessagePortBase;
-using mozilla::dom::MessagePortIdentifier;
-using mozilla::dom::Optional;
-using mozilla::dom::Sequence;
-using mozilla::dom::AutoNoJSAPI;
-using namespace mozilla;
-
-USING_WORKERS_NAMESPACE
-
-namespace {
-
-class DelayedEventRunnable final : public WorkerRunnable
-{
- nsRefPtr<mozilla::dom::workers::MessagePort> mMessagePort;
- nsTArray<nsCOMPtr<nsIDOMEvent>> mEvents;
-
-public:
- DelayedEventRunnable(WorkerPrivate* aWorkerPrivate,
- TargetAndBusyBehavior aBehavior,
- mozilla::dom::workers::MessagePort* aMessagePort,
- nsTArray<nsCOMPtr<nsIDOMEvent>>& aEvents)
- : WorkerRunnable(aWorkerPrivate, aBehavior), mMessagePort(aMessagePort)
- {
- AssertIsOnMainThread();
- MOZ_ASSERT(aMessagePort);
- MOZ_ASSERT(aEvents.Length());
-
- mEvents.SwapElements(aEvents);
- }
-
- bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
- {
- if (mBehavior == WorkerThreadModifyBusyCount) {
- return aWorkerPrivate->ModifyBusyCount(aCx, true);
- }
-
- return true;
- }
-
- void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
- bool aDispatchResult)
- {
- if (!aDispatchResult) {
- if (mBehavior == WorkerThreadModifyBusyCount) {
- aWorkerPrivate->ModifyBusyCount(aCx, false);
- }
- if (aCx) {
- JS_ReportPendingException(aCx);
- }
- }
- }
-
- bool
- WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
-};
-
-} // namespace
-
-BEGIN_WORKERS_NAMESPACE
-
-MessagePort::MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
- uint64_t aSerial)
-: MessagePortBase(aWindow), mSharedWorker(aSharedWorker),
- mWorkerPrivate(nullptr), mSerial(aSerial), mStarted(false)
-{
- AssertIsOnMainThread();
- MOZ_ASSERT(aSharedWorker);
-}
-
-MessagePort::MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial)
-: mWorkerPrivate(aWorkerPrivate), mSerial(aSerial), mStarted(false)
-{
- aWorkerPrivate->AssertIsOnWorkerThread();
-}
-
-MessagePort::~MessagePort()
-{
- Close();
-}
-
-void
-MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
- const Optional<Sequence<JS::Value>>& aTransferable,
- ErrorResult& aRv)
-{
- AssertCorrectThread();
-
- if (IsClosed()) {
- aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
- return;
- }
-
- if (mSharedWorker) {
- mSharedWorker->PostMessage(aCx, aMessage, aTransferable, aRv);
- }
- else {
- mWorkerPrivate->PostMessageToParentMessagePort(aCx, Serial(), aMessage,
- aTransferable, aRv);
- }
-}
-
-void
-MessagePort::Start()
-{
- AssertCorrectThread();
-
- if (IsClosed()) {
- NS_WARNING("Called start() after calling close()!");
- return;
- }
-
- if (mStarted) {
- return;
- }
-
- mStarted = true;
-
- if (!mQueuedEvents.IsEmpty()) {
- WorkerPrivate* workerPrivate;
- WorkerRunnable::TargetAndBusyBehavior behavior;
-
- if (mWorkerPrivate) {
- workerPrivate = mWorkerPrivate;
- behavior = WorkerRunnable::WorkerThreadModifyBusyCount;
- }
- else {
- workerPrivate = mSharedWorker->GetWorkerPrivate();
- MOZ_ASSERT(workerPrivate);
-
- behavior = WorkerRunnable::ParentThreadUnchangedBusyCount;
- }
-
- nsRefPtr<DelayedEventRunnable> runnable =
- new DelayedEventRunnable(workerPrivate, behavior, this, mQueuedEvents);
- runnable->Dispatch(nullptr);
- }
-}
-
-void
-MessagePort::Close()
-{
- AssertCorrectThread();
-
- if (!IsClosed()) {
- CloseInternal();
- }
-}
-
-void
-MessagePort::QueueEvent(nsIDOMEvent* aEvent)
-{
- AssertCorrectThread();
- MOZ_ASSERT(aEvent);
- MOZ_ASSERT(!IsClosed());
- MOZ_ASSERT(!mStarted);
-
- mQueuedEvents.AppendElement(aEvent);
-}
-
-EventHandlerNonNull*
-MessagePort::GetOnmessage()
-{
- AssertCorrectThread();
-
- return NS_IsMainThread() ? GetEventHandler(nsGkAtoms::onmessage, EmptyString())
- : GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
-}
-
-void
-MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
-{
- AssertCorrectThread();
-
- if (NS_IsMainThread()) {
- SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
- }
- else {
- SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
- }
-
- Start();
-}
-
-bool
-MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
-{
- NS_WARNING("Haven't implemented structured clone for these ports yet!");
- return false;
-}
-
-void
-MessagePort::CloseInternal()
-{
- AssertCorrectThread();
- MOZ_ASSERT(!IsClosed());
- MOZ_ASSERT_IF(mStarted, mQueuedEvents.IsEmpty());
-
- if (!mStarted) {
- mQueuedEvents.Clear();
- }
-
- mSharedWorker = nullptr;
- mWorkerPrivate = nullptr;
-}
-
-#ifdef DEBUG
-void
-MessagePort::AssertCorrectThread() const
-{
- if (IsClosed()) {
- return; // Can't assert anything if we nulled out our pointers.
- }
-
- MOZ_ASSERT((mSharedWorker || mWorkerPrivate) &&
- !(mSharedWorker && mWorkerPrivate));
-
- if (mSharedWorker) {
- AssertIsOnMainThread();
- }
- else {
- mWorkerPrivate->AssertIsOnWorkerThread();
- }
-}
-#endif
-
-NS_IMPL_ADDREF_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
- DOMEventTargetHelper)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorker)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEvents)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
- DOMEventTargetHelper)
- tmp->Close();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-JSObject*
-MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
- AssertCorrectThread();
-
- return MessagePortBinding::Wrap(aCx, this, aGivenProto);
-}
-
-nsresult
-MessagePort::PreHandleEvent(EventChainPreVisitor& aVisitor)
-{
- AssertCorrectThread();
-
- nsIDOMEvent*& event = aVisitor.mDOMEvent;
-
- if (event) {
- bool preventDispatch = false;
-
- if (IsClosed()) {
- preventDispatch = true;
- } else if (NS_IsMainThread() && mSharedWorker->IsFrozen()) {
- mSharedWorker->QueueEvent(event);
- preventDispatch = true;
- } else if (!mStarted) {
- QueueEvent(event);
- preventDispatch = true;
- }
-
- if (preventDispatch) {
- aVisitor.mCanHandle = false;
- aVisitor.mParentTarget = nullptr;
- return NS_OK;
- }
- }
-
- return DOMEventTargetHelper::PreHandleEvent(aVisitor);
-}
-
-END_WORKERS_NAMESPACE
-
-bool
-DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
-{
- MOZ_ASSERT(mMessagePort);
- mMessagePort->AssertCorrectThread();
- MOZ_ASSERT(mEvents.Length());
-
- AutoNoJSAPI nojsapi;
-
- bool ignored;
- for (uint32_t i = 0; i < mEvents.Length(); i++) {
- mMessagePort->DispatchEvent(mEvents[i], &ignored);
- }
-
- return true;
-}
deleted file mode 100644
--- a/dom/workers/MessagePort.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_workers_messageport_h_
-#define mozilla_dom_workers_messageport_h_
-
-#include "mozilla/dom/workers/Workers.h"
-
-#include "mozilla/DOMEventTargetHelper.h"
-#include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/dom/MessagePort.h"
-
-class nsIDOMEvent;
-class nsPIDOMWindow;
-
-namespace mozilla {
-class EventChainPreVisitor;
-} // namespace mozilla
-
-BEGIN_WORKERS_NAMESPACE
-
-class SharedWorker;
-class WorkerPrivate;
-
-class MessagePort final : public mozilla::dom::MessagePortBase
-{
- friend class SharedWorker;
- friend class WorkerPrivate;
-
- typedef mozilla::ErrorResult ErrorResult;
-
- nsRefPtr<SharedWorker> mSharedWorker;
- WorkerPrivate* mWorkerPrivate;
- nsTArray<nsCOMPtr<nsIDOMEvent>> mQueuedEvents;
- uint64_t mSerial;
- bool mStarted;
-
-public:
- static bool
- PrefEnabled();
-
- virtual void
- PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
- const Optional<Sequence<JS::Value>>& aTransferable,
- ErrorResult& aRv) override;
-
- virtual void
- Start() override;
-
- virtual void
- Close() override;
-
- uint64_t
- Serial() const
- {
- return mSerial;
- }
-
- void
- QueueEvent(nsIDOMEvent* aEvent);
-
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, DOMEventTargetHelper)
-
- virtual EventHandlerNonNull*
- GetOnmessage() override;
-
- virtual void
- SetOnmessage(EventHandlerNonNull* aCallback) override;
-
- virtual bool
- CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
-
- bool
- IsClosed() const
- {
- return !mSharedWorker && !mWorkerPrivate;
- }
-
- virtual JSObject*
- WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
- virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
-
-#ifdef DEBUG
- void
- AssertCorrectThread() const;
-#else
- void
- AssertCorrectThread() const { }
-#endif
-
-private:
- // This class can only be created by SharedWorker or WorkerPrivate.
- MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
- uint64_t aSerial);
- MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial);
-
- // This class is reference-counted and will be destroyed from Release().
- ~MessagePort();
-
- void
- CloseInternal();
-};
-
-END_WORKERS_NAMESPACE
-
-#endif // mozilla_dom_workers_messageport_h_
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -29,16 +29,17 @@
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/asmjscache/AsmJSCache.h"
#include "mozilla/dom/AtomList.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ErrorEventBinding.h"
#include "mozilla/dom/EventTargetBinding.h"
+#include "mozilla/dom/MessageChannel.h"
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/Navigator.h"
@@ -2488,34 +2489,43 @@ RuntimeService::CreateSharedWorkerFromLo
// Keep a reference to the window before spawning the worker. If the worker is
// a Shared/Service worker and the worker script loads and executes before
// the SharedWorker object itself is created before then WorkerScriptLoaded()
// will reset the loadInfo's window.
nsCOMPtr<nsPIDOMWindow> window = aLoadInfo->mWindow;
bool created = false;
+ ErrorResult rv;
if (!workerPrivate) {
- ErrorResult rv;
workerPrivate =
WorkerPrivate::Constructor(aCx, aScriptURL, false,
aType, aName, aLoadInfo, rv);
NS_ENSURE_TRUE(workerPrivate, rv.StealNSResult());
created = true;
} else {
// If we're attaching to an existing SharedWorker private, then we
// must update the overriden load group to account for our document's
// load group.
workerPrivate->UpdateOverridenLoadGroup(aLoadInfo->mLoadGroup);
}
- nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate);
-
- if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker)) {
+ // We don't actually care about this MessageChannel, but we use it to 'steal'
+ // its 2 connected ports.
+ nsRefPtr<MessageChannel> channel = MessageChannel::Constructor(window, rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ return rv.StealNSResult();
+ }
+
+ nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate,
+ channel->Port1());
+
+ if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker,
+ channel->Port2())) {
NS_WARNING("Worker is unreachable, this shouldn't happen!");
sharedWorker->Close();
return NS_ERROR_FAILURE;
}
// This is normally handled in RegisterWorker, but that wasn't called if the
// worker already existed.
if (!created) {
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -133,18 +133,17 @@ private:
EmptyString(),
EmptyString(),
nullptr);
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(aCx, rv.StealNSResult());
return NS_ERROR_FAILURE;
}
- nsTArray<nsRefPtr<MessagePortBase>> ports;
- TakeTransferredPorts(ports);
+ nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
nsRefPtr<MessagePortList> portList =
new MessagePortList(static_cast<dom::Event*>(event.get()),
ports);
event->SetPorts(portList);
event->SetTrusted(true);
bool status = false;
--- a/dom/workers/ServiceWorkerRegistrar.cpp
+++ b/dom/workers/ServiceWorkerRegistrar.cpp
@@ -6,16 +6,17 @@
#include "ServiceWorkerRegistrar.h"
#include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
#include "nsIEventTarget.h"
#include "nsIInputStream.h"
#include "nsILineInputStream.h"
#include "nsIObserverService.h"
+#include "nsIOutputStream.h"
#include "nsISafeOutputStream.h"
#include "MainThreadUtils.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/ModuleUtils.h"
--- a/dom/workers/SharedWorker.cpp
+++ b/dom/workers/SharedWorker.cpp
@@ -5,42 +5,40 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedWorker.h"
#include "nsPIDOMWindow.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/Preferences.h"
+#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/SharedWorkerBinding.h"
#include "nsContentUtils.h"
#include "nsIClassInfoImpl.h"
#include "nsIDOMEvent.h"
-#include "MessagePort.h"
#include "RuntimeService.h"
#include "WorkerPrivate.h"
using mozilla::dom::Optional;
using mozilla::dom::Sequence;
using namespace mozilla;
USING_WORKERS_NAMESPACE
SharedWorker::SharedWorker(nsPIDOMWindow* aWindow,
- WorkerPrivate* aWorkerPrivate)
-: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate),
- mFrozen(false)
+ WorkerPrivate* aWorkerPrivate,
+ MessagePort* aMessagePort)
+: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate)
+, mMessagePort(aMessagePort)
+, mFrozen(false)
{
AssertIsOnMainThread();
MOZ_ASSERT(aWorkerPrivate);
-
- mSerial = aWorkerPrivate->NextMessagePortSerial();
-
- mMessagePort = new MessagePort(aWindow, this, mSerial);
}
SharedWorker::~SharedWorker()
{
AssertIsOnMainThread();
Close();
MOZ_ASSERT(!mWorkerPrivate);
}
@@ -71,23 +69,21 @@ SharedWorker::Constructor(const GlobalOb
if (NS_FAILED(rv)) {
aRv = rv;
return nullptr;
}
return sharedWorker.forget();
}
-already_AddRefed<mozilla::dom::workers::MessagePort>
+MessagePort*
SharedWorker::Port()
{
AssertIsOnMainThread();
-
- nsRefPtr<MessagePort> messagePort = mMessagePort;
- return messagePort.forget();
+ return mMessagePort;
}
void
SharedWorker::Freeze()
{
AssertIsOnMainThread();
MOZ_ASSERT(!IsFrozen());
@@ -152,18 +148,17 @@ void
SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv)
{
AssertIsOnMainThread();
MOZ_ASSERT(mWorkerPrivate);
MOZ_ASSERT(mMessagePort);
- mWorkerPrivate->PostMessageToMessagePort(aCx, mMessagePort->Serial(),
- aMessage, aTransferable, aRv);
+ mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv);
}
void
SharedWorker::NoteDeadWorker(JSContext* aCx)
{
AssertIsOnMainThread();
MOZ_ASSERT(mWorkerPrivate);
--- a/dom/workers/SharedWorker.h
+++ b/dom/workers/SharedWorker.h
@@ -5,61 +5,55 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_workers_sharedworker_h__
#define mozilla_dom_workers_sharedworker_h__
#include "Workers.h"
#include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/dom/workers/bindings/MessagePort.h"
#include "mozilla/DOMEventTargetHelper.h"
class nsIDOMEvent;
class nsPIDOMWindow;
namespace mozilla {
class EventChainPreVisitor;
+
+namespace dom {
+class MessagePort;
+}
} // namespace mozilla
BEGIN_WORKERS_NAMESPACE
-class MessagePort;
class RuntimeService;
class WorkerPrivate;
class SharedWorker final : public DOMEventTargetHelper
{
- friend class MessagePort;
friend class RuntimeService;
typedef mozilla::ErrorResult ErrorResult;
typedef mozilla::dom::GlobalObject GlobalObject;
nsRefPtr<WorkerPrivate> mWorkerPrivate;
nsRefPtr<MessagePort> mMessagePort;
nsTArray<nsCOMPtr<nsIDOMEvent>> mFrozenEvents;
- uint64_t mSerial;
bool mFrozen;
public:
static already_AddRefed<SharedWorker>
Constructor(const GlobalObject& aGlobal, JSContext* aCx,
const nsAString& aScriptURL, const Optional<nsAString>& aName,
ErrorResult& aRv);
- already_AddRefed<mozilla::dom::workers::MessagePort>
+ MessagePort*
Port();
- uint64_t
- Serial() const
- {
- return mSerial;
- }
-
bool
IsFrozen() const
{
return mFrozen;
}
void
Freeze();
@@ -88,17 +82,18 @@ public:
GetWorkerPrivate() const
{
return mWorkerPrivate;
}
private:
// This class can only be created from the RuntimeService.
SharedWorker(nsPIDOMWindow* aWindow,
- WorkerPrivate* aWorkerPrivate);
+ WorkerPrivate* aWorkerPrivate,
+ MessagePort* aMessagePort);
// This class is reference-counted and will be destroyed from Release().
~SharedWorker();
// Only called by MessagePort.
void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -49,16 +49,17 @@
#include "mozilla/dom/ErrorEventBinding.h"
#include "mozilla/dom/Exceptions.h"
#include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/MessageEvent.h"
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/MessagePortList.h"
+#include "mozilla/dom/PMessagePort.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseDebugging.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
#include "mozilla/dom/WorkerGlobalScopeBinding.h"
@@ -83,17 +84,16 @@
#ifdef ANDROID
#include <android/log.h>
#endif
#ifdef DEBUG
#include "nsThreadManager.h"
#endif
-#include "MessagePort.h"
#include "Navigator.h"
#include "Principal.h"
#include "RuntimeService.h"
#include "ScriptLoader.h"
#include "ServiceWorkerManager.h"
#include "ServiceWorkerWindowClient.h"
#include "SharedWorker.h"
#include "WorkerDebuggerManager.h"
@@ -589,31 +589,25 @@ private:
aWorkerPrivate->CloseHandlerFinished();
}
};
class MessageEventRunnable final : public WorkerRunnable
, public StructuredCloneHelper
{
- uint64_t mMessagePortSerial;
- bool mToMessagePort;
-
// This is only used for messages dispatched to a service worker.
nsAutoPtr<ServiceWorkerClientInfo> mEventSource;
public:
MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
- TargetAndBusyBehavior aBehavior,
- bool aToMessagePort, uint64_t aMessagePortSerial)
+ TargetAndBusyBehavior aBehavior)
: WorkerRunnable(aWorkerPrivate, aBehavior)
, StructuredCloneHelper(CloningSupported, TransferringSupported,
SameProcessDifferentThread)
- , mMessagePortSerial(aMessagePortSerial)
- , mToMessagePort(aToMessagePort)
{
}
void
SetMessageSource(ServiceWorkerClientInfo* aSource)
{
mEventSource = aSource;
}
@@ -649,72 +643,52 @@ public:
event->SetSource(client);
}
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(aCx, rv.StealNSResult());
return false;
}
- nsTArray<nsRefPtr<MessagePortBase>> ports;
- TakeTransferredPorts(ports);
+ nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
event->SetTrusted(true);
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
ports));
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
nsEventStatus dummy = nsEventStatus_eIgnore;
aTarget->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
return true;
}
private:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
- MOZ_ASSERT_IF(mToMessagePort, aWorkerPrivate->IsSharedWorker());
-
if (mBehavior == ParentThreadUnchangedBusyCount) {
// Don't fire this event if the JS object has been disconnected from the
// private object.
if (!aWorkerPrivate->IsAcceptingEvents()) {
return true;
}
- if (mToMessagePort) {
- return
- aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
- mMessagePortSerial,
- *this);
- }
-
if (aWorkerPrivate->IsFrozen()) {
aWorkerPrivate->QueueRunnable(this);
return true;
}
aWorkerPrivate->AssertInnerWindowIsCorrect();
return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate,
!aWorkerPrivate->GetParent());
}
MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
- if (mToMessagePort) {
- nsRefPtr<workers::MessagePort> port =
- aWorkerPrivate->GetMessagePort(mMessagePortSerial);
- if (!port) {
- // Must have been closed already.
- return true;
- }
- return DispatchDOMEvent(aCx, aWorkerPrivate, port, false);
- }
-
return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(),
false);
}
};
class DebuggerMessageEventRunnable : public WorkerDebuggerRunnable {
nsString mMessage;
@@ -1516,42 +1490,38 @@ public:
extras->location = nullptr;
aCompartmentStats->extra = extras;
}
};
class MessagePortRunnable final : public WorkerRunnable
{
- uint64_t mMessagePortSerial;
- bool mConnect;
+ MessagePortIdentifier mPortIdentifier;
public:
MessagePortRunnable(WorkerPrivate* aWorkerPrivate,
- uint64_t aMessagePortSerial,
- bool aConnect)
- : WorkerRunnable(aWorkerPrivate, aConnect ?
- WorkerThreadModifyBusyCount :
- WorkerThreadUnchangedBusyCount),
- mMessagePortSerial(aMessagePortSerial), mConnect(aConnect)
- { }
+ MessagePort* aPort)
+ : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
+ {
+ MOZ_ASSERT(aPort);
+ // In order to move the port from one thread to another one, we have to
+ // close and disentangle it. The output will be a MessagePortIdentifier that
+ // will be used to recreate a new MessagePort on the other thread.
+ aPort->CloneAndDisentangle(mPortIdentifier);
+ }
private:
~MessagePortRunnable()
{ }
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
- if (mConnect) {
- return aWorkerPrivate->ConnectMessagePort(aCx, mMessagePortSerial);
- }
-
- aWorkerPrivate->DisconnectMessagePort(mMessagePortSerial);
- return true;
+ return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
}
};
class DummyRunnable final
: public WorkerRunnable
{
public:
explicit
@@ -2117,18 +2087,17 @@ WorkerPrivateParent<Derived>::WorkerPriv
WorkerType aWorkerType,
const nsACString& aSharedWorkerName,
WorkerLoadInfo& aLoadInfo)
: mMutex("WorkerPrivateParent Mutex"),
mCondVar(mMutex, "WorkerPrivateParent CondVar"),
mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
mParent(aParent), mScriptURL(aScriptURL),
mSharedWorkerName(aSharedWorkerName), mLoadingWorkerScript(false),
- mBusyCount(0), mMessagePortSerial(0),
- mParentStatus(Pending), mParentFrozen(false),
+ mBusyCount(0), mParentStatus(Pending), mParentFrozen(false),
mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
mWorkerType(aWorkerType),
mCreationTimeStamp(TimeStamp::Now()),
mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
{
MOZ_ASSERT_IF(!IsDedicatedWorker(),
!aSharedWorkerName.IsVoid() && NS_IsMainThread());
MOZ_ASSERT_IF(IsDedicatedWorker(), aSharedWorkerName.IsEmpty());
@@ -2482,65 +2451,39 @@ bool
WorkerPrivateParent<Derived>::Freeze(JSContext* aCx, nsPIDOMWindow* aWindow)
{
AssertIsOnParentThread();
MOZ_ASSERT(aCx);
// Shared workers are only frozen if all of their owning documents are
// frozen. It can happen that mSharedWorkers is empty but this thread has
// not been unregistered yet.
- if ((IsSharedWorker() || IsServiceWorker()) && mSharedWorkers.Count()) {
+ if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
AssertIsOnMainThread();
- struct Closure
- {
- nsPIDOMWindow* mWindow;
- bool mAllFrozen;
-
- explicit Closure(nsPIDOMWindow* aWindow)
- : mWindow(aWindow), mAllFrozen(true)
- {
- AssertIsOnMainThread();
- // aWindow may be null here.
+ bool allFrozen = false;
+
+ for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
+ if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
+ // Calling Freeze() may change the refcount, ensure that the worker
+ // outlives this call.
+ nsRefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
+
+ mSharedWorkers[i]->Freeze();
+ } else {
+ MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
+ !SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
+ aWindow));
+ if (!mSharedWorkers[i]->IsFrozen()) {
+ allFrozen = false;
+ }
}
-
- static PLDHashOperator
- Freeze(const uint64_t& aKey,
- SharedWorker* aSharedWorker,
- void* aClosure)
- {
- AssertIsOnMainThread();
- MOZ_ASSERT(aSharedWorker);
- MOZ_ASSERT(aClosure);
-
- auto closure = static_cast<Closure*>(aClosure);
-
- if (closure->mWindow && aSharedWorker->GetOwner() == closure->mWindow) {
- // Calling Freeze() may change the refcount, ensure that the worker
- // outlives this call.
- nsRefPtr<SharedWorker> kungFuDeathGrip = aSharedWorker;
-
- aSharedWorker->Freeze();
- } else {
- MOZ_ASSERT_IF(aSharedWorker->GetOwner() && closure->mWindow,
- !SameCOMIdentity(aSharedWorker->GetOwner(),
- closure->mWindow));
- if (!aSharedWorker->IsFrozen()) {
- closure->mAllFrozen = false;
- }
- }
- return PL_DHASH_NEXT;
- }
- };
-
- Closure closure(aWindow);
-
- mSharedWorkers.EnumerateRead(Closure::Freeze, &closure);
-
- if (!closure.mAllFrozen || mParentFrozen) {
+ }
+
+ if (!allFrozen || mParentFrozen) {
return true;
}
}
mParentFrozen = true;
{
MutexAutoLock lock(mMutex);
@@ -2571,66 +2514,40 @@ WorkerPrivateParent<Derived>::Thaw(JSCon
// parent was actually suspended (maybe during a sync XHR), and in this case
// we don't need to thaw.
return true;
}
// Shared workers are resumed if any of their owning documents are thawed.
// It can happen that mSharedWorkers is empty but this thread has not been
// unregistered yet.
- if ((IsSharedWorker() || IsServiceWorker()) && mSharedWorkers.Count()) {
+ if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
AssertIsOnMainThread();
- struct Closure
- {
- nsPIDOMWindow* mWindow;
- bool mAnyRunning;
-
- explicit Closure(nsPIDOMWindow* aWindow)
- : mWindow(aWindow), mAnyRunning(false)
- {
- AssertIsOnMainThread();
- // aWindow may be null here.
+ bool anyRunning = false;
+
+ for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
+ if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
+ // Calling Thaw() may change the refcount, ensure that the worker
+ // outlives this call.
+ nsRefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
+
+ mSharedWorkers[i]->Thaw();
+ anyRunning = true;
+ } else {
+ MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
+ !SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
+ aWindow));
+ if (!mSharedWorkers[i]->IsFrozen()) {
+ anyRunning = true;
+ }
}
-
- static PLDHashOperator
- Thaw(const uint64_t& aKey,
- SharedWorker* aSharedWorker,
- void* aClosure)
- {
- AssertIsOnMainThread();
- MOZ_ASSERT(aSharedWorker);
- MOZ_ASSERT(aClosure);
-
- auto closure = static_cast<Closure*>(aClosure);
-
- if (closure->mWindow && aSharedWorker->GetOwner() == closure->mWindow) {
- // Calling Thaw() may change the refcount, ensure that the worker
- // outlives this call.
- nsRefPtr<SharedWorker> kungFuDeathGrip = aSharedWorker;
-
- aSharedWorker->Thaw();
- closure->mAnyRunning = true;
- } else {
- MOZ_ASSERT_IF(aSharedWorker->GetOwner() && closure->mWindow,
- !SameCOMIdentity(aSharedWorker->GetOwner(),
- closure->mWindow));
- if (!aSharedWorker->IsFrozen()) {
- closure->mAnyRunning = true;
- }
- }
- return PL_DHASH_NEXT;
- }
- };
-
- Closure closure(aWindow);
-
- mSharedWorkers.EnumerateRead(Closure::Thaw, &closure);
-
- if (!closure.mAnyRunning || !mParentFrozen) {
+ }
+
+ if (!anyRunning || !mParentFrozen) {
return true;
}
}
MOZ_ASSERT(mParentFrozen);
mParentFrozen = false;
@@ -2757,18 +2674,16 @@ WorkerPrivateParent<Derived>::ForgetMain
}
template <class Derived>
void
WorkerPrivateParent<Derived>::PostMessageInternal(
JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
- bool aToMessagePort,
- uint64_t aMessagePortSerial,
ServiceWorkerClientInfo* aClientInfo,
ErrorResult& aRv)
{
AssertIsOnParentThread();
{
MutexAutoLock lock(mMutex);
if (mParentStatus > Running) {
@@ -2792,18 +2707,17 @@ WorkerPrivateParent<Derived>::PostMessag
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
transferable.setObject(*array);
}
nsRefPtr<MessageEventRunnable> runnable =
new MessageEventRunnable(ParentAsWorkerPrivate(),
- WorkerRunnable::WorkerThreadModifyBusyCount,
- aToMessagePort, aMessagePortSerial);
+ WorkerRunnable::WorkerThreadModifyBusyCount);
runnable->Write(aCx, aMessage, transferable, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
runnable->SetMessageSource(aClientInfo);
@@ -2816,98 +2730,17 @@ template <class Derived>
void
WorkerPrivateParent<Derived>::PostMessageToServiceWorker(
JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
ErrorResult& aRv)
{
AssertIsOnMainThread();
- PostMessageInternal(aCx, aMessage, aTransferable, false, 0,
- aClientInfo.forget(), aRv);
-}
-
-template <class Derived>
-void
-WorkerPrivateParent<Derived>::PostMessageToMessagePort(
- JSContext* aCx,
- uint64_t aMessagePortSerial,
- JS::Handle<JS::Value> aMessage,
- const Optional<Sequence<JS::Value>>& aTransferable,
- ErrorResult& aRv)
-{
- AssertIsOnMainThread();
-
- PostMessageInternal(aCx, aMessage, aTransferable, true, aMessagePortSerial,
- nullptr, aRv);
-}
-
-template <class Derived>
-bool
-WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
- JSContext* aCx, uint64_t aMessagePortSerial,
- StructuredCloneHelper& aHelper)
-{
- AssertIsOnMainThread();
-
- SharedWorker* sharedWorker;
- if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
- // SharedWorker has already been unregistered?
- return true;
- }
-
- nsRefPtr<MessagePort> port = sharedWorker->Port();
- NS_ASSERTION(port, "SharedWorkers always have a port!");
-
- if (port->IsClosed()) {
- return true;
- }
-
- nsCOMPtr<nsISupports> parent = do_QueryInterface(port->GetParentObject());
-
- AutoJSAPI jsapi;
- if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) {
- return false;
- }
- JSContext* cx = jsapi.cx();
-
- ErrorResult rv;
- JS::Rooted<JS::Value> data(cx);
- aHelper.Read(parent, cx, &data, rv);
- if (NS_WARN_IF(rv.Failed())) {
- xpc::Throw(cx, rv.StealNSResult());
- return false;
- }
-
- nsRefPtr<MessageEvent> event = new MessageEvent(port, nullptr, nullptr);
- rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data,
- EmptyString(), EmptyString(), nullptr);
- if (NS_WARN_IF(rv.Failed())) {
- xpc::Throw(cx, rv.StealNSResult());
- return false;
- }
-
- nsTArray<nsRefPtr<MessagePortBase>> ports;
- aHelper.TakeTransferredPorts(ports);
-
- event->SetTrusted(true);
- event->SetPorts(new MessagePortList(port, ports));
-
- nsCOMPtr<nsIDOMEvent> domEvent;
- CallQueryInterface(event.get(), getter_AddRefs(domEvent));
- NS_ASSERTION(domEvent, "This should never fail!");
-
- bool ignored;
- rv = port->DispatchEvent(domEvent, &ignored);
- if (NS_WARN_IF(rv.Failed())) {
- xpc::Throw(cx, rv.StealNSResult());
- return false;
- }
-
- return true;
+ PostMessageInternal(aCx, aMessage, aTransferable, aClientInfo.forget(), aRv);
}
template <class Derived>
void
WorkerPrivateParent<Derived>::UpdateRuntimeOptions(
JSContext* aCx,
const JS::RuntimeOptions& aRuntimeOptions)
{
@@ -3085,67 +2918,60 @@ WorkerPrivate::OfflineStatusChangeEventI
event->SetTrusted(true);
globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
}
template <class Derived>
bool
WorkerPrivateParent<Derived>::RegisterSharedWorker(JSContext* aCx,
- SharedWorker* aSharedWorker)
+ SharedWorker* aSharedWorker,
+ MessagePort* aPort)
{
AssertIsOnMainThread();
MOZ_ASSERT(aSharedWorker);
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
- MOZ_ASSERT(!mSharedWorkers.Get(aSharedWorker->Serial()));
+ MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
if (IsSharedWorker()) {
nsRefPtr<MessagePortRunnable> runnable =
- new MessagePortRunnable(ParentAsWorkerPrivate(), aSharedWorker->Serial(),
- true);
+ new MessagePortRunnable(ParentAsWorkerPrivate(), aPort);
if (!runnable->Dispatch(aCx)) {
return false;
}
}
- mSharedWorkers.Put(aSharedWorker->Serial(), aSharedWorker);
+ mSharedWorkers.AppendElement(aSharedWorker);
// If there were other SharedWorker objects attached to this worker then they
// may all have been frozen and this worker would need to be thawed.
- if (mSharedWorkers.Count() > 1 && !Thaw(aCx, nullptr)) {
+ if (mSharedWorkers.Length() > 1 && !Thaw(aCx, nullptr)) {
return false;
}
return true;
}
template <class Derived>
void
WorkerPrivateParent<Derived>::UnregisterSharedWorker(
JSContext* aCx,
SharedWorker* aSharedWorker)
{
AssertIsOnMainThread();
MOZ_ASSERT(aSharedWorker);
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
- MOZ_ASSERT(mSharedWorkers.Get(aSharedWorker->Serial()));
-
- nsRefPtr<MessagePortRunnable> runnable =
- new MessagePortRunnable(ParentAsWorkerPrivate(), aSharedWorker->Serial(),
- false);
- if (!runnable->Dispatch(aCx)) {
- JS_ReportPendingException(aCx);
- }
-
- mSharedWorkers.Remove(aSharedWorker->Serial());
+ MOZ_ASSERT(mSharedWorkers.Contains(aSharedWorker));
+
+ mSharedWorkers.RemoveElement(aSharedWorker);
// If there are still SharedWorker objects attached to this worker then they
// may all be frozen and this worker would need to be frozen. Otherwise,
// if that was the last SharedWorker then it's time to cancel this worker.
- if (mSharedWorkers.Count()) {
+ if (!mSharedWorkers.IsEmpty()) {
if (!Freeze(aCx, nullptr)) {
JS_ReportPendingException(aCx);
}
} else if (!Cancel(aCx)) {
JS_ReportPendingException(aCx);
}
}
@@ -3273,91 +3099,47 @@ WorkerPrivateParent<Derived>::BroadcastE
template <class Derived>
void
WorkerPrivateParent<Derived>::GetAllSharedWorkers(
nsTArray<nsRefPtr<SharedWorker>>& aSharedWorkers)
{
AssertIsOnMainThread();
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
- struct Helper
- {
- static PLDHashOperator
- Collect(const uint64_t& aKey,
- SharedWorker* aSharedWorker,
- void* aClosure)
- {
- AssertIsOnMainThread();
- MOZ_ASSERT(aSharedWorker);
- MOZ_ASSERT(aClosure);
-
- auto array = static_cast<nsTArray<nsRefPtr<SharedWorker>>*>(aClosure);
- array->AppendElement(aSharedWorker);
-
- return PL_DHASH_NEXT;
- }
- };
-
if (!aSharedWorkers.IsEmpty()) {
aSharedWorkers.Clear();
}
- mSharedWorkers.EnumerateRead(Helper::Collect, &aSharedWorkers);
+ for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
+ aSharedWorkers.AppendElement(mSharedWorkers[i]);
+ }
}
template <class Derived>
void
WorkerPrivateParent<Derived>::CloseSharedWorkersForWindow(
nsPIDOMWindow* aWindow)
{
AssertIsOnMainThread();
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
MOZ_ASSERT(aWindow);
- struct Closure
- {
- nsPIDOMWindow* mWindow;
- nsAutoTArray<nsRefPtr<SharedWorker>, 10> mSharedWorkers;
-
- explicit Closure(nsPIDOMWindow* aWindow)
- : mWindow(aWindow)
- {
- AssertIsOnMainThread();
- MOZ_ASSERT(aWindow);
- }
-
- static PLDHashOperator
- Collect(const uint64_t& aKey,
- SharedWorker* aSharedWorker,
- void* aClosure)
- {
- AssertIsOnMainThread();
- MOZ_ASSERT(aSharedWorker);
- MOZ_ASSERT(aClosure);
-
- auto closure = static_cast<Closure*>(aClosure);
- MOZ_ASSERT(closure->mWindow);
-
- if (aSharedWorker->GetOwner() == closure->mWindow) {
- closure->mSharedWorkers.AppendElement(aSharedWorker);
- } else {
- MOZ_ASSERT(!SameCOMIdentity(aSharedWorker->GetOwner(),
- closure->mWindow));
- }
-
- return PL_DHASH_NEXT;
- }
- };
-
- Closure closure(aWindow);
-
- mSharedWorkers.EnumerateRead(Closure::Collect, &closure);
-
- for (uint32_t index = 0; index < closure.mSharedWorkers.Length(); index++) {
- closure.mSharedWorkers[index]->Close();
+ nsAutoTArray<nsRefPtr<SharedWorker>, 10> sharedWorkers;
+
+ for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
+ if (mSharedWorkers[i]->GetOwner() == aWindow) {
+ sharedWorkers.AppendElement(mSharedWorkers[i]);
+ } else {
+ MOZ_ASSERT(!SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
+ aWindow));
+ }
+ }
+
+ for (uint32_t index = 0; index < sharedWorkers.Length(); index++) {
+ sharedWorkers[index]->Close();
}
}
template <class Derived>
void
WorkerPrivateParent<Derived>::WorkerScriptLoaded()
{
AssertIsOnMainThread();
@@ -4583,19 +4365,16 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
if (!mControlQueue.IsEmpty()) {
WorkerControlRunnable* runnable;
while (mControlQueue.Pop(runnable)) {
runnable->Cancel();
runnable->Release();
}
}
- // Clear away our MessagePorts.
- mWorkerPorts.Clear();
-
// Unroot the globals
mScope = nullptr;
mDebuggerScope = nullptr;
return;
}
}
@@ -5523,18 +5302,16 @@ WorkerPrivate::AssertValidSyncLoop(nsIEv
}
#endif
void
WorkerPrivate::PostMessageToParentInternal(
JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
- bool aToMessagePort,
- uint64_t aMessagePortSerial,
ErrorResult& aRv)
{
AssertIsOnWorkerThread();
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
if (aTransferable.WasPassed()) {
const Sequence<JS::Value>& realTransferable = aTransferable.Value();
@@ -5549,50 +5326,29 @@ WorkerPrivate::PostMessageToParentIntern
aRv = NS_ERROR_OUT_OF_MEMORY;
return;
}
transferable.setObject(*array);
}
nsRefPtr<MessageEventRunnable> runnable =
new MessageEventRunnable(this,
- WorkerRunnable::ParentThreadUnchangedBusyCount,
- aToMessagePort, aMessagePortSerial);
+ WorkerRunnable::ParentThreadUnchangedBusyCount);
runnable->Write(aCx, aMessage, transferable, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (!runnable->Dispatch(aCx)) {
aRv = NS_ERROR_FAILURE;
}
}
void
-WorkerPrivate::PostMessageToParentMessagePort(
- JSContext* aCx,
- uint64_t aMessagePortSerial,
- JS::Handle<JS::Value> aMessage,
- const Optional<Sequence<JS::Value>>& aTransferable,
- ErrorResult& aRv)
-{
- AssertIsOnWorkerThread();
-
- if (!mWorkerPorts.GetWeak(aMessagePortSerial)) {
- // This port has been closed from the main thread. There's no point in
- // sending this message so just bail.
- return;
- }
-
- PostMessageToParentInternal(aCx, aMessage, aTransferable, true,
- aMessagePortSerial, aRv);
-}
-
-void
WorkerPrivate::EnterDebuggerEventLoop()
{
AssertIsOnWorkerThread();
JSContext* cx = GetJSContext();
MOZ_ASSERT(cx);
uint32_t currentEventLoopLevel = ++mDebuggerEventLoopLevel;
@@ -6439,85 +6195,65 @@ WorkerPrivate::EndCTypesCall()
mBlockedForMemoryReporter = false;
}
// Make sure the periodic timer is running before we start running JS again.
SetGCTimerMode(PeriodicTimer);
}
bool
-WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial)
+WorkerPrivate::ConnectMessagePort(JSContext* aCx,
+ MessagePortIdentifier& aIdentifier)
{
AssertIsOnWorkerThread();
- NS_ASSERTION(!mWorkerPorts.GetWeak(aMessagePortSerial),
- "Already have this port registered!");
-
WorkerGlobalScope* globalScope = GlobalScope();
JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
MOZ_ASSERT(jsGlobal);
- nsRefPtr<MessagePort> port = new MessagePort(this, aMessagePortSerial);
+ // This MessagePortIdentifier is used to create a new port, still connected
+ // with the other one, but in the worker thread.
+ ErrorResult rv;
+ nsRefPtr<MessagePort> port = MessagePort::Create(nullptr, aIdentifier, rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ return false;
+ }
GlobalObject globalObject(aCx, jsGlobal);
if (globalObject.Failed()) {
return false;
}
RootedDictionary<MessageEventInit> init(aCx);
init.mBubbles = false;
init.mCancelable = false;
init.mSource.SetValue().SetAsMessagePort() = port;
- ErrorResult rv;
-
nsRefPtr<MessageEvent> event =
MessageEvent::Constructor(globalObject,
NS_LITERAL_STRING("connect"), init, rv);
event->SetTrusted(true);
- nsTArray<nsRefPtr<MessagePortBase>> ports;
+ nsTArray<nsRefPtr<MessagePort>> ports;
ports.AppendElement(port);
nsRefPtr<MessagePortList> portList =
new MessagePortList(static_cast<nsIDOMEventTarget*>(globalScope), ports);
event->SetPorts(portList);
- mWorkerPorts.Put(aMessagePortSerial, port);
-
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
nsEventStatus dummy = nsEventStatus_eIgnore;
globalScope->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
+
return true;
}
-void
-WorkerPrivate::DisconnectMessagePort(uint64_t aMessagePortSerial)
-{
- AssertIsOnWorkerThread();
-
- mWorkerPorts.Remove(aMessagePortSerial);
-}
-
-workers::MessagePort*
-WorkerPrivate::GetMessagePort(uint64_t aMessagePortSerial)
-{
- AssertIsOnWorkerThread();
-
- nsRefPtr<MessagePort> port;
- if (mWorkerPorts.Get(aMessagePortSerial, getter_AddRefs(port))) {
- return port;
- }
-
- return nullptr;
-}
-
WorkerGlobalScope*
WorkerPrivate::GetOrCreateGlobalScope(JSContext* aCx)
{
AssertIsOnWorkerThread();
if (!mScope) {
nsRefPtr<WorkerGlobalScope> globalScope;
if (IsSharedWorker()) {
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -45,31 +45,32 @@ class nsIURI;
namespace JS {
struct RuntimeStats;
} // namespace JS
namespace mozilla {
namespace dom {
class Function;
+class MessagePort;
+class MessagePortIdentifier;
class StructuredCloneHelper;
} // namespace dom
namespace ipc {
class PrincipalInfo;
} // namespace ipc
} // namespace mozilla
struct PRThread;
class ReportDebuggerErrorRunnable;
BEGIN_WORKERS_NAMESPACE
class AutoSyncLoopHolder;
-class MessagePort;
class SharedWorker;
class ServiceWorkerClientInfo;
class WorkerControlRunnable;
class WorkerDebugger;
class WorkerDebuggerGlobalScope;
class WorkerGlobalScope;
class WorkerPrivate;
class WorkerRunnable;
@@ -172,20 +173,19 @@ private:
// Only used for top level workers.
nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
// Protected by mMutex.
JSSettings mJSSettings;
// Only touched on the parent thread (currently this is always the main
// thread as SharedWorkers are always top-level).
- nsDataHashtable<nsUint64HashKey, SharedWorker*> mSharedWorkers;
+ nsTArray<SharedWorker*> mSharedWorkers;
uint64_t mBusyCount;
- uint64_t mMessagePortSerial;
Status mParentStatus;
bool mParentFrozen;
bool mIsChromeWorker;
bool mMainThreadObjectsForgotten;
WorkerType mWorkerType;
TimeStamp mCreationTimeStamp;
DOMHighResTimeStamp mCreationTimeHighRes;
TimeStamp mNowBaseTimeStamp;
@@ -221,17 +221,16 @@ private:
TerminatePrivate(JSContext* aCx)
{
return NotifyPrivate(aCx, Terminating);
}
void
PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
- bool aToMessagePort, uint64_t aMessagePortSerial,
ServiceWorkerClientInfo* aClientInfo,
ErrorResult& aRv);
nsresult
DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable, nsIEventTarget* aSyncLoopTarget);
public:
virtual JSObject*
@@ -323,39 +322,26 @@ public:
void
ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value> >& aTransferable,
ErrorResult& aRv)
{
- PostMessageInternal(aCx, aMessage, aTransferable, false, 0, nullptr, aRv);
+ PostMessageInternal(aCx, aMessage, aTransferable, nullptr, aRv);
}
void
PostMessageToServiceWorker(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
ErrorResult& aRv);
void
- PostMessageToMessagePort(JSContext* aCx,
- uint64_t aMessagePortSerial,
- JS::Handle<JS::Value> aMessage,
- const Optional<Sequence<JS::Value> >& aTransferable,
- ErrorResult& aRv);
-
- bool
- DispatchMessageEventToMessagePort(
- JSContext* aCx,
- uint64_t aMessagePortSerial,
- StructuredCloneHelper& aHelper);
-
- void
UpdateRuntimeOptions(JSContext* aCx,
const JS::RuntimeOptions& aRuntimeOptions);
void
UpdateLanguages(JSContext* aCx, const nsTArray<nsString>& aLanguages);
void
UpdatePreference(JSContext* aCx, WorkerPreference aPref, bool aValue);
@@ -374,17 +360,18 @@ public:
void
CycleCollect(JSContext* aCx, bool aDummy);
void
OfflineStatusChangeEvent(JSContext* aCx, bool aIsOffline);
bool
- RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
+ RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker,
+ MessagePort* aPort);
void
UnregisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
void
BroadcastErrorToSharedWorkers(JSContext* aCx,
const nsAString& aMessage,
const nsAString& aFilename,
@@ -753,23 +740,16 @@ public:
}
const nsCString&
SharedWorkerName() const
{
return mSharedWorkerName;
}
- uint64_t
- NextMessagePortSerial()
- {
- AssertIsOnMainThread();
- return mMessagePortSerial++;
- }
-
bool
IsStorageAllowed() const
{
return mLoadInfo.mStorageAllowed;
}
bool
IsInPrivateBrowsing() const
@@ -947,18 +927,16 @@ class WorkerPrivate : public WorkerPriva
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsITimer> mGCTimer;
nsCOMPtr<nsIEventTarget> mPeriodicGCTimerTarget;
nsCOMPtr<nsIEventTarget> mIdleGCTimerTarget;
nsRefPtr<MemoryReporter> mMemoryReporter;
- nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts;
-
// fired on the main thread if the worker script fails to load
nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
TimeStamp mKillTime;
uint32_t mErrorHandlerRecursionCount;
uint32_t mNextTimeoutId;
Status mStatus;
bool mFrozen;
@@ -1071,23 +1049,22 @@ public:
}
void
PostMessageToParent(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv)
{
- PostMessageToParentInternal(aCx, aMessage, aTransferable, false, 0, aRv);
+ PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv);
}
void
PostMessageToParentMessagePort(
JSContext* aCx,
- uint64_t aMessagePortSerial,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv);
void
EnterDebuggerEventLoop();
void
@@ -1234,23 +1211,17 @@ public:
EndCTypesCallback()
{
// If a callback is ending then we need to do the exact same thing as
// when a ctypes call begins.
BeginCTypesCall();
}
bool
- ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial);
-
- void
- DisconnectMessagePort(uint64_t aMessagePortSerial);
-
- MessagePort*
- GetMessagePort(uint64_t aMessagePortSerial);
+ ConnectMessagePort(JSContext* aCx, MessagePortIdentifier& aIdentifier);
WorkerGlobalScope*
GetOrCreateGlobalScope(JSContext* aCx);
WorkerDebuggerGlobalScope*
CreateDebuggerGlobalScope(JSContext* aCx);
bool
@@ -1440,18 +1411,16 @@ private:
void
WaitForWorkerEvents(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT);
void
PostMessageToParentInternal(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
- bool aToMessagePort,
- uint64_t aMessagePortSerial,
ErrorResult& aRv);
void
GetAllPreferences(bool aPreferences[WORKERPREF_COUNT]) const
{
AssertIsOnWorkerThread();
memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool));
}
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -24,17 +24,16 @@ EXPORTS.mozilla.dom.workers += [
]
# Stuff needed for the bindings, not really public though.
EXPORTS.mozilla.dom.workers.bindings += [
'DataStore.h',
'DataStoreCursor.h',
'FileReaderSync.h',
'Location.h',
- 'MessagePort.h',
'Navigator.h',
'Performance.h',
'ServiceWorker.h',
'ServiceWorkerClient.h',
'ServiceWorkerClients.h',
'ServiceWorkerWindowClient.h',
'SharedWorker.h',
'URL.h',
@@ -51,17 +50,16 @@ XPIDL_SOURCES += [
]
UNIFIED_SOURCES += [
'ChromeWorkerScope.cpp',
'DataStore.cpp',
'DataStoreCursor.cpp',
'FileReaderSync.cpp',
'Location.cpp',
- 'MessagePort.cpp',
'Navigator.cpp',
'Performance.cpp',
'Principal.cpp',
'RegisterBindings.cpp',
'RuntimeService.cpp',
'ScriptLoader.cpp',
'ServiceWorker.cpp',
'ServiceWorkerClient.cpp',
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -105,16 +105,17 @@ support-files =
bug1132395_sharedWorker.js
bug1132924_worker.js
empty.html
worker_performance_user_timing.js
worker_performance_observer.js
sharedworker_performance_user_timing.js
referrer.sjs
performance_observer.html
+ sharedWorker_ports.js
[test_404.html]
[test_atob.html]
[test_blobConstructor.html]
[test_blobWorkers.html]
[test_bug949946.html]
[test_bug978260.html]
[test_bug998474.html]
@@ -216,8 +217,9 @@ skip-if = buildapp == 'b2g' || toolkit =
skip-if = buildapp == 'b2g' || e10s
[test_xhr_responseURL.html]
[test_xhr_system.html]
skip-if = buildapp == 'b2g' || e10s
[test_xhr_timeout.html]
skip-if = (os == "win") || (os == "mac") || toolkit == 'android' || e10s #bug 798220
[test_xhrAbort.html]
[test_referrer.html]
+[test_sharedWorker_ports.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/sharedWorker_ports.js
@@ -0,0 +1,23 @@
+var port;
+onconnect = function(evt) {
+ evt.source.postMessage({ type: "connected" });
+
+ if (!port) {
+ port = evt.source;
+ evt.source.onmessage = function(evtFromPort) {
+ port.postMessage({type: "status",
+ test: "Port from the main-thread!" == evtFromPort.data,
+ msg: "The message is coming from the main-thread"});
+ port.postMessage({type: "status",
+ test: (evtFromPort.ports.length == 1),
+ msg: "1 port transferred"});
+
+ evtFromPort.ports[0].onmessage = function(evtFromPort2) {
+ port.postMessage({type: "status",
+ test: (evtFromPort2.data.type == "connected"),
+ msg: "The original message received" });
+ port.postMessage({type: "finish"});
+ }
+ }
+ }
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_sharedWorker_ports.html
@@ -0,0 +1,42 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Test for MessagePort and SharedWorkers</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ </head>
+ <body>
+ <script class="testbody" type="text/javascript">
+
+SpecialPowers.pushPrefEnv({ set: [["dom.workers.sharedWorkers.enabled", true]]},
+function() {
+ var sw1 = new SharedWorker('sharedWorker_ports.js');
+ sw1.port.onmessage = function(event) {
+ if (event.data.type == "connected") {
+ ok(true, "The SharedWorker is alive.");
+
+ var sw2 = new SharedWorker('sharedWorker_ports.js');
+ sw1.port.postMessage("Port from the main-thread!", [sw2.port]);
+ return;
+ }
+
+ if (event.data.type == "status") {
+ ok(event.data.test, event.data.msg);
+ return;
+ }
+
+ if (event.data.type == "finish") {
+ SimpleTest.finish();
+ }
+ }
+});
+
+SimpleTest.waitForExplicitFinish();
+ </script>
+ </body>
+</html>
+