Bug 1174624 - Add the Transferable parameter into SendAsyncMessage of nsFrameMessageManager. r=baku
authorMantaroh Yoshinaga <mantaroh@gmail.com>
Sun, 31 Jan 2016 22:48:00 +0100
changeset 321362 7d2bc215980907d791c942ae3b8783a97b060d34
parent 321361 807683706e4ed63cd348a3c748bcc028cb4c3d3e
child 321363 8e7a30a8f6c8ee1a4c55f1d97571270b5aa41731
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1174624
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1174624 - Add the Transferable parameter into SendAsyncMessage of nsFrameMessageManager. r=baku
dom/base/StructuredCloneHolder.cpp
dom/base/nsFrameMessageManager.cpp
dom/base/nsFrameMessageManager.h
dom/base/nsIMessageManager.idl
dom/ipc/DOMTypes.ipdlh
dom/ipc/StructuredCloneData.cpp
dom/ipc/StructuredCloneData.h
dom/messagechannel/MessagePort.cpp
dom/messagechannel/MessagePort.h
dom/messagechannel/PMessagePort.ipdl
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -1036,26 +1036,22 @@ StructuredCloneHolder::CustomReadTransfe
                                                  uint32_t aTag,
                                                  void* aContent,
                                                  uint64_t aExtraData,
                                                  JS::MutableHandleObject aReturnObject)
 {
   MOZ_ASSERT(mSupportsTransferring);
 
   if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
-    // This can be null.
-    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
-
     MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
     const MessagePortIdentifier& portIdentifier = mPortIdentifiers[aExtraData];
 
-    // aExtraData is the index of this port identifier.
     ErrorResult rv;
     RefPtr<MessagePort> port =
-      MessagePort::Create(window, portIdentifier, rv);
+      MessagePort::Create(mParent, 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/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -28,16 +28,18 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsIDOMClassInfo.h"
 #include "xpcpublic.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/IntentionalCrash.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/File.h"
+#include "mozilla/dom/MessagePort.h"
+#include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/nsIContentParent.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/ProcessGlobal.h"
 #include "mozilla/dom/SameProcessMessageQueue.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
@@ -269,16 +271,18 @@ template<ActorFlavorEnum Flavor>
 static bool
 BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
                        StructuredCloneData& aData,
                        ClonedMessageData& aClonedData)
 {
   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
   buffer.data = aData.Data();
   buffer.dataLength = aData.DataLength();
+  aClonedData.identfiers().AppendElements(aData.PortIdentifiers());
+
   const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
 
   if (!blobImpls.IsEmpty()) {
     typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
     InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
     uint32_t length = blobImpls.Length();
     blobList.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
@@ -312,19 +316,22 @@ MessageManagerCallback::BuildClonedMessa
 template<ActorFlavorEnum Flavor>
 static void
 UnpackClonedMessageData(const ClonedMessageData& aClonedData,
                         StructuredCloneData& aData)
 {
   const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
   typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
   const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aClonedData);
+  const InfallibleTArray<MessagePortIdentifier>& identifiers = aClonedData.identfiers();
 
   aData.UseExternalData(buffer.data, buffer.dataLength);
 
+  aData.PortIdentifiers().AppendElements(identifiers);
+
   if (!blobs.IsEmpty()) {
     uint32_t length = blobs.Length();
     aData.BlobImpls().SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       auto* blob =
         static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
       MOZ_ASSERT(blob);
 
@@ -611,22 +618,24 @@ JSONCreator(const char16_t* aBuf, uint32
   result->Append(static_cast<const char16_t*>(aBuf),
                  static_cast<uint32_t>(aLen));
   return true;
 }
 
 static bool
 GetParamsForMessage(JSContext* aCx,
                     const JS::Value& aValue,
+                    const JS::Value& aTransfer,
                     StructuredCloneData& aData)
 {
   // First try to use structured clone on the whole thing.
   JS::RootedValue v(aCx, aValue);
+  JS::RootedValue t(aCx, aTransfer);
   ErrorResult rv;
-  aData.Write(aCx, v, rv);
+  aData.Write(aCx, v, t, rv);
   if (!rv.Failed()) {
     return true;
   }
 
   rv.SuppressException();
   JS_ClearPendingException(aCx);
 
   nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
@@ -711,17 +720,17 @@ nsFrameMessageManager::SendMessage(const
   NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
 
   if (sSendingSyncMessage && aIsSync) {
     // No kind of blocking send should be issued on top of a sync message.
     return NS_ERROR_UNEXPECTED;
   }
 
   StructuredCloneData data;
-  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, data)) {
+  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, JS::UndefinedHandleValue, data)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   JS::Rooted<JSObject*> objects(aCx);
   if (aArgc >= 3 && aObjects.isObject()) {
     objects = &aObjects.toObject();
   }
 
@@ -786,60 +795,61 @@ nsFrameMessageManager::DispatchAsyncMess
   return NS_OK;
 }
 
 nsresult
 nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
                                             const JS::Value& aJSON,
                                             const JS::Value& aObjects,
                                             nsIPrincipal* aPrincipal,
+                                            const JS::Value& aTransfers,
                                             JSContext* aCx,
                                             uint8_t aArgc)
 {
   StructuredCloneData data;
-  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, data)) {
+  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, aTransfers, data)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   JS::Rooted<JSObject*> objects(aCx);
   if (aArgc >= 3 && aObjects.isObject()) {
     objects = &aObjects.toObject();
   }
 
   return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects,
                                       aPrincipal);
 }
 
-
 // nsIMessageSender
 
 NS_IMETHODIMP
 nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
                                         JS::Handle<JS::Value> aJSON,
                                         JS::Handle<JS::Value> aObjects,
                                         nsIPrincipal* aPrincipal,
+                                        JS::Handle<JS::Value> aTransfers,
                                         JSContext* aCx,
                                         uint8_t aArgc)
 {
-  return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx,
-                              aArgc);
+  return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aPrincipal,
+                              aTransfers, aCx, aArgc);
 }
 
 
 // nsIMessageBroadcaster
 
 NS_IMETHODIMP
 nsFrameMessageManager::BroadcastAsyncMessage(const nsAString& aMessageName,
                                              JS::Handle<JS::Value> aJSON,
                                              JS::Handle<JS::Value> aObjects,
                                              JSContext* aCx,
                                              uint8_t aArgc)
 {
-  return DispatchAsyncMessage(aMessageName, aJSON, aObjects, nullptr, aCx,
-                              aArgc);
+  return DispatchAsyncMessage(aMessageName, aJSON, aObjects, nullptr,
+                              JS::UndefinedHandleValue, aCx, aArgc);
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::GetChildCount(uint32_t* aChildCount)
 {
   *aChildCount = static_cast<uint32_t>(mChildManagers.Count());
   return NS_OK;
 }
@@ -1136,28 +1146,44 @@ nsFrameMessageManager::ReceiveMessage(ns
         ErrorResult rv;
         aCloneData->Read(cx, &json, rv);
         if (NS_WARN_IF(rv.Failed())) {
           rv.SuppressException();
           JS_ClearPendingException(cx);
           return NS_OK;
         }
       }
+
+      // Get cloned MessagePort from StructuredCloneData.
+      nsTArray<RefPtr<mozilla::dom::MessagePort>> ports;
+      if (aCloneData) {
+        ports = aCloneData->TakeTransferredPorts();
+      }
+
+      JS::Rooted<JSObject*> transferredList(cx);
+      RefPtr<MessagePortList> portList = new MessagePortList(aTargetFrameLoader, ports);
+      transferredList = portList->WrapObject(cx, nullptr);
+      if (NS_WARN_IF(!transferredList)) {
+        return NS_ERROR_UNEXPECTED;
+      }
+
       JS::Rooted<JSString*> jsMessage(cx,
         JS_NewUCStringCopyN(cx,
                             static_cast<const char16_t*>(aMessage.BeginReading()),
                             aMessage.Length()));
       NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY);
       JS::Rooted<JS::Value> syncv(cx, JS::BooleanValue(aIsSync));
       bool ok = JS_DefineProperty(cx, param, "target", targetv, JSPROP_ENUMERATE) &&
                 JS_DefineProperty(cx, param, "name", jsMessage, JSPROP_ENUMERATE) &&
                 JS_DefineProperty(cx, param, "sync", syncv, JSPROP_ENUMERATE) &&
                 JS_DefineProperty(cx, param, "json", json, JSPROP_ENUMERATE) && // deprecated
                 JS_DefineProperty(cx, param, "data", json, JSPROP_ENUMERATE) &&
-                JS_DefineProperty(cx, param, "objects", cpowsv, JSPROP_ENUMERATE);
+                JS_DefineProperty(cx, param, "objects", cpowsv, JSPROP_ENUMERATE) &&
+                JS_DefineProperty(cx, param, "ports", transferredList, JSPROP_ENUMERATE);
+
       NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
 
       if (aTargetFrameLoader) {
         JS::Rooted<JS::Value> targetFrameLoaderv(cx);
         nsresult rv = nsContentUtils::WrapNative(cx, aTargetFrameLoader, &targetFrameLoaderv);
         NS_ENSURE_SUCCESS(rv, rv);
 
         ok = JS_DefineProperty(cx, param, "targetFrameLoader", targetFrameLoaderv,
--- a/dom/base/nsFrameMessageManager.h
+++ b/dom/base/nsFrameMessageManager.h
@@ -210,18 +210,20 @@ public:
   {
     return mCallback;
   }
 
   nsresult DispatchAsyncMessage(const nsAString& aMessageName,
                                 const JS::Value& aJSON,
                                 const JS::Value& aObjects,
                                 nsIPrincipal* aPrincipal,
+                                const JS::Value& aTransfers,
                                 JSContext* aCx,
                                 uint8_t aArgc);
+
   nsresult DispatchAsyncMessageInternal(JSContext* aCx,
                                         const nsAString& aMessage,
                                         StructuredCloneData& aData,
                                         JS::Handle<JSObject*> aCpows,
                                         nsIPrincipal* aPrincipal);
   void RemoveFromParent();
   nsFrameMessageManager* GetParentManager() { return mParentManager; }
   void SetParentManager(nsFrameMessageManager* aParent)
--- a/dom/base/nsIMessageManager.idl
+++ b/dom/base/nsIMessageManager.idl
@@ -277,17 +277,18 @@ interface nsIMessageSender : nsIMessageL
    * @throws NS_ERROR_FAILURE when the message receiver cannot be found.  For
    *         example, we will throw NS_ERROR_FAILURE if we try to send a message
    *         to a cross-process frame whose process has crashed.
    */
   [implicit_jscontext, optional_argc]
   void sendAsyncMessage([optional] in AString messageName,
                         [optional] in jsval obj,
                         [optional] in jsval objects,
-                        [optional] in nsIPrincipal principal);
+                        [optional] in nsIPrincipal principal,
+                        [optional] in jsval transfers);
 };
 
 /**
  * Message "broadcasters" don't have a single "other side" that they
  * send messages to, but rather a set of subordinate message managers.
  * For example, broadcasting a message through a window message
  * manager will broadcast the message to all frame message managers
  * within its window.
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -19,20 +19,29 @@ namespace mozilla {
 namespace dom {
 
 union OptionalID
 {
   nsID;
   void_t;
 };
 
+struct MessagePortIdentifier
+{
+  nsID uuid;
+  nsID destinationUuid;
+  uint32_t sequenceId;
+  bool neutered;
+};
+
 struct ClonedMessageData
 {
   SerializedStructuredCloneBuffer data;
   PBlob[] blobs;
+  MessagePortIdentifier[] identfiers;
 };
 
 union BlobData
 {
   // For remote blobs.
   nsID;
 
   // For memory-backed blobs.
--- a/dom/ipc/StructuredCloneData.cpp
+++ b/dom/ipc/StructuredCloneData.cpp
@@ -62,19 +62,28 @@ StructuredCloneData::Read(JSContext* aCx
   ReadFromBuffer(global, aCx, Data(), DataLength(), aValue, aRv);
 }
 
 void
 StructuredCloneData::Write(JSContext* aCx,
                            JS::Handle<JS::Value> aValue,
                            ErrorResult &aRv)
 {
+  Write(aCx, aValue, JS::UndefinedHandleValue, aRv);
+}
+
+void
+StructuredCloneData::Write(JSContext* aCx,
+                           JS::Handle<JS::Value> aValue,
+                           JS::Handle<JS::Value> aTransfer,
+                           ErrorResult &aRv)
+{
   MOZ_ASSERT(!Data());
 
-  StructuredCloneHolder::Write(aCx, aValue, aRv);
+  StructuredCloneHolder::Write(aCx, aValue, aTransfer, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   uint64_t* data = nullptr;
   size_t dataLength = 0;
   mBuffer->steal(&data, &dataLength);
   mBuffer = nullptr;
--- a/dom/ipc/StructuredCloneData.h
+++ b/dom/ipc/StructuredCloneData.h
@@ -65,17 +65,17 @@ private:
   size_t mDataLength;
 };
 
 class StructuredCloneData : public StructuredCloneHolder
 {
 public:
   StructuredCloneData()
     : StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
-                            StructuredCloneHolder::TransferringNotSupported,
+                            StructuredCloneHolder::TransferringSupported,
                             StructuredCloneHolder::DifferentProcess)
     , mExternalData(nullptr)
     , mExternalDataLength(0)
   {}
 
   StructuredCloneData(const StructuredCloneData&) = delete;
 
   ~StructuredCloneData()
@@ -101,16 +101,21 @@ public:
   void Read(JSContext* aCx,
             JS::MutableHandle<JS::Value> aValue,
             ErrorResult &aRv);
 
   void Write(JSContext* aCx,
              JS::Handle<JS::Value> aValue,
              ErrorResult &aRv);
 
+  void Write(JSContext* aCx,
+             JS::Handle<JS::Value> aValue,
+             JS::Handle<JS::Value> aTransfers,
+             ErrorResult &aRv);
+
   void UseExternalData(uint64_t* aData, size_t aDataLength)
   {
     MOZ_ASSERT(!Data());
     mExternalData = aData;
     mExternalDataLength = aDataLength;
   }
 
   bool CopyExternalData(const void* aData, size_t aDataLength);
--- a/dom/messagechannel/MessagePort.cpp
+++ b/dom/messagechannel/MessagePort.cpp
@@ -99,23 +99,20 @@ private:
     AutoJSAPI jsapi;
     if (!globalObject || !jsapi.Init(globalObject)) {
       NS_WARNING("Failed to initialize AutoJSAPI object.");
       return NS_ERROR_FAILURE;
     }
 
     JSContext* cx = jsapi.cx();
 
-    nsCOMPtr<nsPIDOMWindowInner> window =
-      do_QueryInterface(mPort->GetParentObject());
-
     ErrorResult rv;
     JS::Rooted<JS::Value> value(cx);
 
-    mData->Read(window, cx, &value, rv);
+    mData->Read(mPort->GetParentObject(), cx, &value, rv);
     if (NS_WARN_IF(rv.Failed())) {
       return rv.StealNSResult();
     }
 
     // Create the event
     nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
       do_QueryInterface(mPort->GetOwner());
     RefPtr<MessageEvent> event =
@@ -257,49 +254,54 @@ private:
 
   const MessagePortIdentifier mIdentifier;
 };
 
 NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback)
 
 } // namespace
 
-MessagePort::MessagePort(nsPIDOMWindowInner* aWindow)
-  : DOMEventTargetHelper(aWindow)
-  , mInnerID(0)
+MessagePort::MessagePort(nsISupports* aSupports)
+  : mInnerID(0)
   , mMessageQueueEnabled(false)
   , mIsKeptAlive(false)
 {
   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(nsPIDOMWindowInner* aWindow, const nsID& aUUID,
+MessagePort::Create(nsISupports* aSupport, const nsID& aUUID,
                     const nsID& aDestinationUUID, ErrorResult& aRv)
 {
-  RefPtr<MessagePort> mp = new MessagePort(aWindow);
+  RefPtr<MessagePort> mp = new MessagePort(aSupport);
   mp->Initialize(aUUID, aDestinationUUID, 1 /* 0 is an invalid sequence ID */,
                  false /* Neutered */, eStateUnshippedEntangled, aRv);
   return mp.forget();
 }
 
 /* static */ already_AddRefed<MessagePort>
-MessagePort::Create(nsPIDOMWindowInner* aWindow,
+MessagePort::Create(nsISupports* aSupport,
                     const MessagePortIdentifier& aIdentifier,
                     ErrorResult& aRv)
 {
-  RefPtr<MessagePort> mp = new MessagePort(aWindow);
+  RefPtr<MessagePort> mp = new MessagePort(aSupport);
   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
@@ -40,21 +40,21 @@ 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(nsPIDOMWindowInner* aWindow, const nsID& aUUID,
+  Create(nsISupports* aSupport, const nsID& aUUID,
          const nsID& aDestinationUUID, ErrorResult& aRv);
 
   static already_AddRefed<MessagePort>
-  Create(nsPIDOMWindowInner* aWindow, const MessagePortIdentifier& aIdentifier,
+  Create(nsISupports* aSupport, 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 +83,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(nsPIDOMWindowInner* aWindow);
+  explicit MessagePort(nsISupports* nsISupports);
   ~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/messagechannel/PMessagePort.ipdl
+++ b/dom/messagechannel/PMessagePort.ipdl
@@ -1,28 +1,20 @@
 /* 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 protocol PBackground;
 include protocol PBlob;
 
-using struct nsID from "nsID.h";
+include DOMTypes;
 
 namespace mozilla {
 namespace dom {
 
-struct MessagePortIdentifier
-{
-  nsID uuid;
-  nsID destinationUuid;
-  uint32_t sequenceId;
-  bool neutered;
-};
-
 struct MessagePortMessage
 {
   MessagePortIdentifier[] transferredPorts;
   uint8_t[] data;
   PBlob[] blobs;
 };
 
 // This protocol is used for the MessageChannel/MessagePort API