Bug 1353629 - PBlob refactoring - part 3 - IPCBlob in ClonedMessageData, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 24 Apr 2017 12:09:40 +0200
changeset 354618 e257576d44a4bcee8eef180c67f5f2318def5d90
parent 354617 989411dbd27c982f01d47f924bbe5e1d68b39dbd
child 354619 e9400156bf733aa1a928969529eea5d5e6ed7f98
push id31707
push userkwierso@gmail.com
push dateMon, 24 Apr 2017 22:53:41 +0000
treeherdermozilla-central@abdcc8dfc283 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1353629
milestone55.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 1353629 - PBlob refactoring - part 3 - IPCBlob in ClonedMessageData, r=smaug This is the first use of IPCBlob: ClonedMessageData. ClonedMessageData is used for BroadcastChannel, MessagePort and any postMessage() communication. This patch changes StructuredCloneData in order to use IPCBlob instead of PBlob. BroadcastChannel has a custom way to manage Blobs because when the parent receives them from a content process, it must send them to any other BroadcastChild actor duplicating the serialization.
dom/broadcastchannel/BroadcastChannelParent.cpp
dom/broadcastchannel/BroadcastChannelParent.h
dom/broadcastchannel/BroadcastChannelService.cpp
dom/ipc/DOMTypes.ipdlh
dom/ipc/PBrowser.ipdl
dom/ipc/StructuredCloneData.cpp
dom/ipc/StructuredCloneData.h
--- a/dom/broadcastchannel/BroadcastChannelParent.cpp
+++ b/dom/broadcastchannel/BroadcastChannelParent.cpp
@@ -2,18 +2,19 @@
 /* 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 "BroadcastChannelParent.h"
 #include "BroadcastChannelService.h"
 #include "mozilla/dom/File.h"
-#include "mozilla/dom/ipc/BlobParent.h"
+#include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/ipc/IPCStreamUtils.h"
 #include "mozilla/Unused.h"
 #include "nsIScriptSecurityManager.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
@@ -68,35 +69,10 @@ BroadcastChannelParent::ActorDestroy(Act
 
   if (mService) {
     // This object is about to be released and with it, also mService will be
     // released too.
     mService->UnregisterActor(this, mOriginChannelKey);
   }
 }
 
-void
-BroadcastChannelParent::Deliver(const ClonedMessageData& aData)
-{
-  AssertIsOnBackgroundThread();
-
-  // Duplicate the data for this parent.
-  ClonedMessageData newData(aData);
-
-  // Create new BlobParent objects for this message.
-  for (uint32_t i = 0, len = newData.blobsParent().Length(); i < len; ++i) {
-    RefPtr<BlobImpl> impl =
-      static_cast<BlobParent*>(newData.blobsParent()[i])->GetBlobImpl();
-
-    PBlobParent* blobParent =
-      BackgroundParent::GetOrCreateActorForBlobImpl(Manager(), impl);
-    if (!blobParent) {
-      return;
-    }
-
-    newData.blobsParent()[i] = blobParent;
-  }
-
-  Unused << SendNotify(newData);
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/broadcastchannel/BroadcastChannelParent.h
+++ b/dom/broadcastchannel/BroadcastChannelParent.h
@@ -21,19 +21,16 @@ namespace dom {
 class BroadcastChannelService;
 
 class BroadcastChannelParent final : public PBroadcastChannelParent
 {
   friend class mozilla::ipc::BackgroundParentImpl;
 
   typedef mozilla::ipc::PrincipalInfo PrincipalInfo;
 
-public:
-  void Deliver(const ClonedMessageData& aData);
-
 private:
   explicit BroadcastChannelParent(const nsAString& aOriginChannelKey);
   ~BroadcastChannelParent();
 
   virtual mozilla::ipc::IPCResult
   RecvPostMessage(const ClonedMessageData& aData) override;
 
   virtual mozilla::ipc::IPCResult RecvClose() override;
--- a/dom/broadcastchannel/BroadcastChannelService.cpp
+++ b/dom/broadcastchannel/BroadcastChannelService.cpp
@@ -2,17 +2,17 @@
 /* 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 "BroadcastChannelService.h"
 #include "BroadcastChannelParent.h"
 #include "mozilla/dom/File.h"
-#include "mozilla/dom/ipc/BlobParent.h"
+#include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/ipc/BackgroundParent.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
 namespace mozilla {
 
@@ -101,32 +101,50 @@ BroadcastChannelService::PostMessage(Bro
   MOZ_ASSERT(aParent);
 
   nsTArray<BroadcastChannelParent*>* parents;
   if (!mAgents.Get(aOriginChannelKey, &parents)) {
     MOZ_CRASH("Invalid state");
   }
 
   // We need to keep the array alive for the life-time of this operation.
-  nsTArray<RefPtr<BlobImpl>> blobs;
-  if (!aData.blobsParent().IsEmpty()) {
-    blobs.SetCapacity(aData.blobsParent().Length());
+  nsTArray<RefPtr<BlobImpl>> blobImpls;
+  if (!aData.blobs().IsEmpty()) {
+    blobImpls.SetCapacity(aData.blobs().Length());
 
-    for (uint32_t i = 0, len = aData.blobsParent().Length(); i < len; ++i) {
-      RefPtr<BlobImpl> impl =
-        static_cast<BlobParent*>(aData.blobsParent()[i])->GetBlobImpl();
-     MOZ_ASSERT(impl);
-     blobs.AppendElement(impl);
+    for (uint32_t i = 0, len = aData.blobs().Length(); i < len; ++i) {
+      RefPtr<BlobImpl> impl = IPCBlobUtils::Deserialize(aData.blobs()[i]);
+
+      MOZ_ASSERT(impl);
+      blobImpls.AppendElement(impl);
     }
   }
 
+  // For each parent actor, we notify the message.
   for (uint32_t i = 0; i < parents->Length(); ++i) {
     BroadcastChannelParent* parent = parents->ElementAt(i);
     MOZ_ASSERT(parent);
 
-    if (parent != aParent) {
-      parent->Deliver(aData);
+    if (parent == aParent) {
+      continue;
     }
+
+    // We need to have a copy of the data for this parent.
+    ClonedMessageData newData(aData);
+    MOZ_ASSERT(blobImpls.Length() == newData.blobs().Length());
+
+    if (!blobImpls.IsEmpty()) {
+      // Serialize Blob objects for this message.
+      for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
+        nsresult rv = IPCBlobUtils::Serialize(blobImpls[i], parent->Manager(),
+                                              newData.blobs()[i]);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return;
+        }
+      }
+    }
+
+    Unused << parent->SendNotify(newData);
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -2,16 +2,17 @@
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* 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 PBlob;
 include protocol PMemoryStream;
 
+include IPCBlob;
 include IPCStream;
 include ProtocolTypes;
 
 using struct mozilla::void_t
   from "ipc/IPCMessageUtils.h";
 
 using struct mozilla::SerializedStructuredCloneBuffer
   from "ipc/IPCMessageUtils.h";
@@ -36,17 +37,17 @@ struct MessagePortIdentifier
  * Cross-process representation for postMessage() style payloads where Blobs may
  * be referenced/"cloned" and (optionally) messageports transferred.  Use
  * StructuredCloneData in your code to convert between this wire representation
  * and the StructuredCloneData StructuredCloneHolder-subclass.
  */
 struct ClonedMessageData
 {
   SerializedStructuredCloneBuffer data;
-  PBlob[] blobs;
+  IPCBlob[] blobs;
   IPCStream[] inputStreams;
   MessagePortIdentifier[] identfiers;
 };
 
 struct BlobDataStream
 {
   PMemoryStream stream;
   uint64_t length;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -15,16 +15,18 @@ include protocol PFilePicker;
 include protocol PIndexedDBPermissionRequest;
 include protocol PRenderFrame;
 include protocol PPluginWidget;
 include protocol PRemotePrintJob;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PFileDescriptorSet;
 include DOMTypes;
+include IPCBlob;
+include IPCStream;
 include JavaScriptTypes;
 include URIParams;
 include PPrintingTypes;
 include PTabContext;
 
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using class mozilla::gfx::Matrix from "mozilla/gfx/Matrix.h";
--- a/dom/ipc/StructuredCloneData.cpp
+++ b/dom/ipc/StructuredCloneData.cpp
@@ -8,16 +8,17 @@
 
 #include "nsIDOMDOMException.h"
 #include "nsIMutable.h"
 #include "nsIXPConnect.h"
 
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/ipc/IPCStreamUtils.h"
 #include "nsContentUtils.h"
 #include "nsJSEnvironment.h"
 #include "MainThreadUtils.h"
 #include "StructuredCloneTags.h"
 #include "jsapi.h"
 
@@ -137,102 +138,19 @@ enum ActorFlavorEnum {
   Child,
 };
 
 enum ManagerFlavorEnum {
   ContentProtocol = 0,
   BackgroundProtocol
 };
 
-template <ActorFlavorEnum>
-struct BlobTraits
-{ };
-
-template <>
-struct BlobTraits<Parent>
-{
-  typedef mozilla::dom::BlobParent BlobType;
-  typedef mozilla::dom::PBlobParent ProtocolType;
-};
-
-template <>
-struct BlobTraits<Child>
-{
-  typedef mozilla::dom::BlobChild BlobType;
-  typedef mozilla::dom::PBlobChild ProtocolType;
-};
-
-template <ActorFlavorEnum, ManagerFlavorEnum>
-struct ParentManagerTraits
-{ };
-
-template<>
-struct ParentManagerTraits<Parent, ContentProtocol>
-{
-  typedef mozilla::dom::nsIContentParent ConcreteContentManagerType;
-};
-
-template<>
-struct ParentManagerTraits<Child, ContentProtocol>
-{
-  typedef mozilla::dom::nsIContentChild ConcreteContentManagerType;
-};
-
-template<>
-struct ParentManagerTraits<Parent, BackgroundProtocol>
-{
-  typedef mozilla::ipc::PBackgroundParent ConcreteContentManagerType;
-};
-
-template<>
-struct ParentManagerTraits<Child, BackgroundProtocol>
-{
-  typedef mozilla::ipc::PBackgroundChild ConcreteContentManagerType;
-};
-
-template<ActorFlavorEnum>
-struct DataBlobs
-{ };
-
-template<>
-struct DataBlobs<Parent>
-{
-  typedef BlobTraits<Parent>::ProtocolType ProtocolType;
-
-  static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
-  {
-    return aData.blobsParent();
-  }
-
-  static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
-  {
-    return aData.blobsParent();
-  }
-};
-
-template<>
-struct DataBlobs<Child>
-{
-  typedef BlobTraits<Child>::ProtocolType ProtocolType;
-
-  static InfallibleTArray<ProtocolType*>& Blobs(ClonedMessageData& aData)
-  {
-    return aData.blobsChild();
-  }
-
-  static const InfallibleTArray<ProtocolType*>& Blobs(const ClonedMessageData& aData)
-  {
-    return aData.blobsChild();
-  }
-};
-
-template<ActorFlavorEnum Flavor, ManagerFlavorEnum ManagerFlavor>
-static bool
-BuildClonedMessageData(typename ParentManagerTraits<Flavor, ManagerFlavor>::ConcreteContentManagerType* aManager,
-                       StructuredCloneData& aData,
+template<typename M>
+bool
+BuildClonedMessageData(M* aManager, StructuredCloneData& aData,
                        ClonedMessageData& aClonedData)
 {
   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
   auto iter = aData.Data().Iter();
   size_t size = aData.Data().Size();
   bool success;
   buffer.data = aData.Data().Borrow<js::SystemAllocPolicy>(iter, size, &success);
   if (NS_WARN_IF(!success)) {
@@ -240,33 +158,36 @@ BuildClonedMessageData(typename ParentMa
   }
   if (aData.SupportsTransferring()) {
     aClonedData.identfiers().AppendElements(aData.PortIdentifiers());
   }
 
   const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
 
   if (!blobImpls.IsEmpty()) {
-    typedef typename BlobTraits<Flavor>::BlobType BlobType;
-    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) {
-      BlobType* protocolActor = BlobType::GetOrCreate(aManager, blobImpls[i]);
-      if (!protocolActor) {
+    if (NS_WARN_IF(!aClonedData.blobs().SetLength(blobImpls.Length(), fallible))) {
+      return false;
+    }
+
+    for (uint32_t i = 0; i < blobImpls.Length(); ++i) {
+      nsresult rv = IPCBlobUtils::Serialize(blobImpls[i], aManager,
+                                            aClonedData.blobs()[i]);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
         return false;
       }
-      blobList.AppendElement(protocolActor);
     }
   }
 
   const nsTArray<nsCOMPtr<nsIInputStream>>& inputStreams = aData.InputStreams();
+  if (!inputStreams.IsEmpty()) {
+    if (NS_WARN_IF(!aData.IPCStreams().SetCapacity(inputStreams.Length(),
+                                                   fallible))) {
+      return false;
+    }
 
-  if (!inputStreams.IsEmpty()) {
     InfallibleTArray<IPCStream>& streams = aClonedData.inputStreams();
     uint32_t length = inputStreams.Length();
     streams.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       AutoIPCStream* stream = aData.IPCStreams().AppendElement(fallible);
       if (NS_WARN_IF(!stream)) {
         return false;
       }
@@ -281,41 +202,41 @@ BuildClonedMessageData(typename ParentMa
   return true;
 }
 
 bool
 StructuredCloneData::BuildClonedMessageDataForParent(
   nsIContentParent* aParent,
   ClonedMessageData& aClonedData)
 {
-  return BuildClonedMessageData<Parent, ContentProtocol>(aParent, *this, aClonedData);
+  return BuildClonedMessageData(aParent, *this, aClonedData);
 }
 
 bool
 StructuredCloneData::BuildClonedMessageDataForChild(
   nsIContentChild* aChild,
   ClonedMessageData& aClonedData)
 {
-  return BuildClonedMessageData<Child, ContentProtocol>(aChild, *this, aClonedData);
+  return BuildClonedMessageData(aChild, *this, aClonedData);
 }
 
 bool
 StructuredCloneData::BuildClonedMessageDataForBackgroundParent(
   PBackgroundParent* aParent,
   ClonedMessageData& aClonedData)
 {
-  return BuildClonedMessageData<Parent, BackgroundProtocol>(aParent, *this, aClonedData);
+  return BuildClonedMessageData(aParent, *this, aClonedData);
 }
 
 bool
 StructuredCloneData::BuildClonedMessageDataForBackgroundChild(
   PBackgroundChild* aChild,
   ClonedMessageData& aClonedData)
 {
-  return BuildClonedMessageData<Child, BackgroundProtocol>(aChild, *this, aClonedData);
+  return BuildClonedMessageData(aChild, *this, aClonedData);
 }
 
 // See the StructuredCloneData class block comment for the meanings of each val.
 enum MemoryFlavorEnum {
   BorrowMemory = 0,
   CopyMemory,
   StealMemory
 };
@@ -368,35 +289,30 @@ struct MemoryTraits<StealMemory>
 // and Child/BackgroundChild in this implementation.  The calling methods,
 // however, do maintain the distinction for code-reading purposes and are backed
 // by assertions to enforce there is no misuse.
 template<MemoryFlavorEnum MemoryFlavor, ActorFlavorEnum Flavor>
 static void
 UnpackClonedMessageData(typename MemoryTraits<MemoryFlavor>::ClonedMessageType& aClonedData,
                         StructuredCloneData& aData)
 {
-  typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
-  const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aClonedData);
   const InfallibleTArray<MessagePortIdentifier>& identifiers = aClonedData.identfiers();
 
   MemoryTraits<MemoryFlavor>::ProvideBuffer(aClonedData, aData);
 
   if (aData.SupportsTransferring()) {
     aData.PortIdentifiers().AppendElements(identifiers);
   }
 
+  const nsTArray<IPCBlob>& blobs = aClonedData.blobs();
   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);
-
-      RefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
+      RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(blobs[i]);
       MOZ_ASSERT(blobImpl);
 
       aData.BlobImpls().AppendElement(blobImpl);
     }
   }
 
   const InfallibleTArray<IPCStream>& streams = aClonedData.inputStreams();
   if (!streams.IsEmpty()) {
--- a/dom/ipc/StructuredCloneData.h
+++ b/dom/ipc/StructuredCloneData.h
@@ -198,18 +198,18 @@ public:
 
   void Write(JSContext* aCx,
              JS::Handle<JS::Value> aValue,
              JS::Handle<JS::Value> aTransfers,
              ErrorResult &aRv);
 
   // Actor-varying methods to convert the structured clone stored in this holder
   // by a previous call to Write() into ClonedMessageData IPC representation.
-  // (Blobs are represented in IPC by PBlob actors, so we need the parent to be
-  // able to create them.)
+  // (Blobs are represented in IPC by IPCBlob actors, so we need the parent to
+  // be able to create them.)
   bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
                                        ClonedMessageData& aClonedData);
   bool BuildClonedMessageDataForChild(nsIContentChild* aChild,
                                       ClonedMessageData& aClonedData);
   bool BuildClonedMessageDataForBackgroundParent(mozilla::ipc::PBackgroundParent* aParent,
                                                  ClonedMessageData& aClonedData);
   bool BuildClonedMessageDataForBackgroundChild(mozilla::ipc::PBackgroundChild* aChild,
                                                 ClonedMessageData& aClonedData);