Bug 1250572 - Force a parent object in MessagePort/Channel and in StructuredCloneHolder, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 01 Mar 2016 15:21:11 +0100
changeset 286302 124b690646181b1f4f9747f3d938954b1705e702
parent 286301 7729ce5fd356e3c85aaa6107c7cfcbdc63354ee8
child 286303 0f47155c48a15a3f34e1e59fab90ef244025b61d
push id17930
push userkwierso@gmail.com
push dateTue, 01 Mar 2016 23:30:47 +0000
treeherderfx-team@f4fdf1a5e7e7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1250572
milestone47.0a1
Bug 1250572 - Force a parent object in MessagePort/Channel and in StructuredCloneHolder, r=smaug
dom/base/StructuredCloneHolder.cpp
dom/messagechannel/MessageChannel.cpp
dom/messagechannel/MessageChannel.h
dom/messagechannel/MessagePort.cpp
dom/messagechannel/MessagePort.h
dom/workers/RuntimeService.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/XMLHttpRequest.cpp
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -290,16 +290,17 @@ StructuredCloneHolder::Write(JSContext* 
 void
 StructuredCloneHolder::Read(nsISupports* aParent,
                             JSContext* aCx,
                             JS::MutableHandle<JS::Value> aValue,
                             ErrorResult& aRv)
 {
   MOZ_ASSERT_IF(mSupportedContext == SameProcessSameThread,
                 mCreationThread == NS_GetCurrentThread());
+  MOZ_ASSERT(aParent);
 
   mozilla::AutoRestore<nsISupports*> guard(mParent);
   mParent = aParent;
 
   if (!StructuredCloneHolderBase::Read(aCx, aValue)) {
     JS_ClearPendingException(aCx);
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
   }
@@ -1039,19 +1040,21 @@ StructuredCloneHolder::CustomReadTransfe
                                                  JS::MutableHandleObject aReturnObject)
 {
   MOZ_ASSERT(mSupportsTransferring);
 
   if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
     MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
     const MessagePortIdentifier& portIdentifier = mPortIdentifiers[aExtraData];
 
+    nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
+
     ErrorResult rv;
     RefPtr<MessagePort> port =
-      MessagePort::Create(mParent, portIdentifier, rv);
+      MessagePort::Create(global, portIdentifier, rv);
     if (NS_WARN_IF(rv.Failed())) {
       return false;
     }
 
     mTransferredPorts.AppendElement(port);
 
     JS::Rooted<JS::Value> value(aCx);
     if (!GetOrCreateDOMReflector(aCx, port, &value)) {
--- a/dom/messagechannel/MessageChannel.cpp
+++ b/dom/messagechannel/MessageChannel.cpp
@@ -8,78 +8,80 @@
 
 #include "mozilla/dom/MessageChannelBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "nsContentUtils.h"
 #include "nsIDocument.h"
+#include "nsIGlobalObject.h"
 #include "nsIPrincipal.h"
-#include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mWindow, mPort1, mPort2)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mGlobal, mPort1, mPort2)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-MessageChannel::MessageChannel(nsPIDOMWindowInner* aWindow)
-  : mWindow(aWindow)
+MessageChannel::MessageChannel(nsIGlobalObject* aGlobal)
+  : mGlobal(aGlobal)
 {
+  MOZ_ASSERT(aGlobal);
 }
 
 MessageChannel::~MessageChannel()
 {
 }
 
 JSObject*
 MessageChannel::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return MessageChannelBinding::Wrap(aCx, this, aGivenProto);
 }
 
 /* static */ already_AddRefed<MessageChannel>
 MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
-  // window can be null in workers.
-  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
-  return Constructor(window, aRv);
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
+  return Constructor(global, aRv);
 }
 
 /* static */ already_AddRefed<MessageChannel>
-MessageChannel::Constructor(nsPIDOMWindowInner* aWindow, ErrorResult& aRv)
+MessageChannel::Constructor(nsIGlobalObject* aGlobal, ErrorResult& aRv)
 {
+  MOZ_ASSERT(aGlobal);
+
   nsID portUUID1;
   aRv = nsContentUtils::GenerateUUIDInPlace(portUUID1);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsID portUUID2;
   aRv = nsContentUtils::GenerateUUIDInPlace(portUUID2);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  RefPtr<MessageChannel> channel = new MessageChannel(aWindow);
+  RefPtr<MessageChannel> channel = new MessageChannel(aGlobal);
 
-  channel->mPort1 = MessagePort::Create(aWindow, portUUID1, portUUID2, aRv);
+  channel->mPort1 = MessagePort::Create(aGlobal, portUUID1, portUUID2, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  channel->mPort2 = MessagePort::Create(aWindow, portUUID2, portUUID1, aRv);
+  channel->mPort2 = MessagePort::Create(aGlobal, 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
@@ -9,62 +9,62 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "nsCOMPtr.h"
 
-class nsPIDOMWindowInner;
+class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
 class MessagePort;
 
 class MessageChannel final : public nsISupports
                            , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MessageChannel)
 
-  nsPIDOMWindowInner*
+  nsIGlobalObject*
   GetParentObject() const
   {
-    return mWindow;
+    return mGlobal;
   }
 
   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(nsPIDOMWindowInner* aWindow, ErrorResult& aRv);
+  Constructor(nsIGlobalObject* aGlobal, ErrorResult& aRv);
 
   MessagePort*
   Port1() const
   {
     return mPort1;
   }
 
   MessagePort*
   Port2() const
   {
     return mPort2;
   }
 
 private:
-  explicit MessageChannel(nsPIDOMWindowInner* aWindow);
+  explicit MessageChannel(nsIGlobalObject* aGlobal);
   ~MessageChannel();
 
-  nsCOMPtr<nsPIDOMWindowInner> mWindow;
+  nsCOMPtr<nsIGlobalObject> mGlobal;
 
   RefPtr<MessagePort> mPort1;
   RefPtr<MessagePort> mPort2;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/messagechannel/MessagePort.cpp
+++ b/dom/messagechannel/MessagePort.cpp
@@ -84,25 +84,18 @@ public:
     mData = nullptr;
     return NS_OK;
   }
 
 private:
   nsresult
   DispatchMessage() const
   {
-    nsCOMPtr<nsIGlobalObject> globalObject;
-
-    if (NS_IsMainThread()) {
-      globalObject = do_QueryInterface(mPort->GetParentObject());
-    } else {
-      WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
-      MOZ_ASSERT(workerPrivate);
-      globalObject = workerPrivate->GlobalScope();
-    }
+    nsCOMPtr<nsIGlobalObject> globalObject = mPort->GetParentObject();
+    MOZ_ASSERT(globalObject);
 
     AutoJSAPI jsapi;
     if (!globalObject || !jsapi.Init(globalObject)) {
       NS_WARNING("Failed to initialize AutoJSAPI object.");
       return NS_ERROR_FAILURE;
     }
 
     JSContext* cx = jsapi.cx();
@@ -277,54 +270,55 @@ private:
 
   const MessagePortIdentifier mIdentifier;
 };
 
 NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback)
 
 } // namespace
 
-MessagePort::MessagePort(nsISupports* aSupports)
-  : mInnerID(0)
+MessagePort::MessagePort(nsIGlobalObject* aGlobal)
+  : DOMEventTargetHelper(aGlobal)
+  , mInnerID(0)
   , mMessageQueueEnabled(false)
   , mIsKeptAlive(false)
 {
+  MOZ_ASSERT(aGlobal);
+
   mIdentifier = new MessagePortIdentifier();
   mIdentifier->neutered() = true;
   mIdentifier->sequenceId() = 0;
-
-  nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(aSupports);
-  if (NS_WARN_IF(!globalObject)) {
-    return;
-  }
-  BindToOwner(globalObject);
 }
 
 MessagePort::~MessagePort()
 {
   CloseForced();
   MOZ_ASSERT(!mWorkerFeature);
 }
 
 /* static */ already_AddRefed<MessagePort>
-MessagePort::Create(nsISupports* aSupport, const nsID& aUUID,
+MessagePort::Create(nsIGlobalObject* aGlobal, const nsID& aUUID,
                     const nsID& aDestinationUUID, ErrorResult& aRv)
 {
-  RefPtr<MessagePort> mp = new MessagePort(aSupport);
+  MOZ_ASSERT(aGlobal);
+
+  RefPtr<MessagePort> mp = new MessagePort(aGlobal);
   mp->Initialize(aUUID, aDestinationUUID, 1 /* 0 is an invalid sequence ID */,
                  false /* Neutered */, eStateUnshippedEntangled, aRv);
   return mp.forget();
 }
 
 /* static */ already_AddRefed<MessagePort>
-MessagePort::Create(nsISupports* aSupport,
+MessagePort::Create(nsIGlobalObject* aGlobal,
                     const MessagePortIdentifier& aIdentifier,
                     ErrorResult& aRv)
 {
-  RefPtr<MessagePort> mp = new MessagePort(aSupport);
+  MOZ_ASSERT(aGlobal);
+
+  RefPtr<MessagePort> mp = new MessagePort(aGlobal);
   mp->Initialize(aIdentifier.uuid(), aIdentifier.destinationUuid(),
                  aIdentifier.sequenceId(), aIdentifier.neutered(),
                  eStateEntangling, aRv);
   return mp.forget();
 }
 
 void
 MessagePort::UnshippedEntangle(MessagePort* aEntangledPort)
--- a/dom/messagechannel/MessagePort.h
+++ b/dom/messagechannel/MessagePort.h
@@ -11,17 +11,17 @@
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsIIPCBackgroundChildCreateCallback.h"
 #include "nsTArray.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
-class nsPIDOMWindowInner;
+class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
 class MessagePortChild;
 class MessagePortIdentifier;
 class MessagePortMessage;
 class PostMessageRunnable;
@@ -40,21 +40,22 @@ class MessagePort final : public DOMEven
 public:
   NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
   NS_DECL_NSIOBSERVER
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
                                            DOMEventTargetHelper)
 
   static already_AddRefed<MessagePort>
-  Create(nsISupports* aSupport, const nsID& aUUID,
+  Create(nsIGlobalObject* aGlobal, const nsID& aUUID,
          const nsID& aDestinationUUID, ErrorResult& aRv);
 
   static already_AddRefed<MessagePort>
-  Create(nsISupports* aSupport, const MessagePortIdentifier& aIdentifier,
+  Create(nsIGlobalObject* aGlobal,
+         const MessagePortIdentifier& aIdentifier,
          ErrorResult& aRv);
 
   // For IPC.
   static void
   ForceClose(const MessagePortIdentifier& aIdentifier);
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -83,17 +84,17 @@ public:
   // These methods are useful for MessagePortChild
 
   void Entangled(nsTArray<MessagePortMessage>& aMessages);
   void MessagesReceived(nsTArray<MessagePortMessage>& aMessages);
   void StopSendingDataConfirmed();
   void Closed();
 
 private:
-  explicit MessagePort(nsISupports* nsISupports);
+  explicit MessagePort(nsIGlobalObject* aGlobal);
   ~MessagePort();
 
   enum State {
     // When a port is created by a MessageChannel it is entangled with the
     // other. They both run on the same thread, same event loop and the
     // messages are added to the queues without using PBackground actors.
     // When one of the port is shipped, the state is changed to
     // StateEntangling.
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2283,23 +2283,24 @@ RuntimeService::CreateSharedWorkerFromLo
     // 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);
   }
 
   // We don't actually care about this MessageChannel, but we use it to 'steal'
   // its 2 connected ports.
-  RefPtr<MessageChannel> channel = MessageChannel::Constructor(window, rv);
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
+  RefPtr<MessageChannel> channel = MessageChannel::Constructor(global, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
   RefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate,
-                                                         channel->Port1());
+                                                       channel->Port1());
 
   if (!workerPrivate->RegisterSharedWorker(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
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -663,20 +663,33 @@ public:
   {
     mEventSource = Move(aSource);
   }
 
   bool
   DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                    DOMEventTargetHelper* aTarget, bool aIsMainThread)
   {
-    nsCOMPtr<nsPIDOMWindowInner> parent;
-    if (aIsMainThread) {
-      parent = do_QueryInterface(aTarget->GetParentObject());
-    }
+    nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(aTarget->GetParentObject());
+
+    // For some workers without window, parent is null and we try to find it
+    // from the JS Context.
+    if (!parent) {
+      JS::Rooted<JSObject*> globalObject(aCx, JS::CurrentGlobalOrNull(aCx));
+      if (NS_WARN_IF(!globalObject)) {
+        return false;
+      }
+
+      parent = xpc::NativeGlobal(globalObject);
+      if (NS_WARN_IF(!parent)) {
+        return false;
+      }
+    }
+
+    MOZ_ASSERT(parent);
 
     JS::Rooted<JS::Value> messageData(aCx);
     ErrorResult rv;
 
     UniquePtr<AbstractTimelineMarker> start;
     UniquePtr<AbstractTimelineMarker> end;
     RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
     bool isTimelineRecording = timelines && !timelines->IsEmpty();
@@ -6371,17 +6384,17 @@ WorkerPrivate::ConnectMessagePort(JSCont
   WorkerGlobalScope* globalScope = GlobalScope();
 
   JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
   MOZ_ASSERT(jsGlobal);
 
   // This MessagePortIdentifier is used to create a new port, still connected
   // with the other one, but in the worker thread.
   ErrorResult rv;
-  RefPtr<MessagePort> port = MessagePort::Create(nullptr, aIdentifier, rv);
+  RefPtr<MessagePort> port = MessagePort::Create(globalScope, aIdentifier, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return false;
   }
 
   GlobalObject globalObject(aCx, jsGlobal);
   if (globalObject.Failed()) {
     return false;
   }
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -23,16 +23,17 @@
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 #include "nsVariant.h"
 
 #include "RuntimeService.h"
+#include "WorkerScope.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "XMLHttpRequestUpload.h"
 
 #include "mozilla/UniquePtr.h"
 
 using namespace mozilla;
 
@@ -1350,17 +1351,22 @@ EventRunnable::WorkerRun(JSContext* aCx,
     state->mResponseResult = mResponseResult;
 
     if (NS_SUCCEEDED(mResponseResult)) {
       if (HasData()) {
         MOZ_ASSERT(mResponse.isUndefined());
 
         ErrorResult rv;
         JS::Rooted<JS::Value> response(aCx);
-        Read(nullptr, aCx, &response, rv);
+
+        GlobalObject globalObj(aCx, aWorkerPrivate->GlobalScope()->GetWrapper());
+        nsCOMPtr<nsIGlobalObject> global =
+          do_QueryInterface(globalObj.GetAsSupports());
+
+        Read(global, aCx, &response, rv);
         if (NS_WARN_IF(rv.Failed())) {
           rv.SuppressException();
           return false;
         }
 
         state->mResponse = response;
       }
       else {
@@ -1527,18 +1533,28 @@ SendRunnable::MainThreadRun()
     AutoSafeJSContext cx;
     JSAutoRequest ar(cx);
 
     nsIXPConnect* xpc = nsContentUtils::XPConnect();
     MOZ_ASSERT(xpc);
 
     ErrorResult rv;
 
+    JS::Rooted<JSObject*> globalObject(cx, JS::CurrentGlobalOrNull(cx));
+    if (NS_WARN_IF(!globalObject)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    nsCOMPtr<nsIGlobalObject> parent = xpc::NativeGlobal(globalObject);
+    if (NS_WARN_IF(!parent)) {
+      return NS_ERROR_FAILURE;
+    }
+
     JS::Rooted<JS::Value> body(cx);
-    Read(nullptr, cx, &body, rv);
+    Read(parent, cx, &body, rv);
     if (NS_WARN_IF(rv.Failed())) {
       return rv.StealNSResult();
     }
 
     rv = xpc->JSValToVariant(cx, body, getter_AddRefs(variant));
     if (NS_WARN_IF(rv.Failed())) {
       return rv.StealNSResult();
     }