Bug 1198795 - ipc/StructuredCloneUtils should be merged with StructuredCloneHelper, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 02 Sep 2015 17:20:30 +0100
changeset 281278 ed6830f48c58fcd145c1967f3f879cc67553377d
parent 281277 50fd13696678be08cc9fdd953905fffc72b6aa48
child 281279 c9e469c6b9159e42c83dacdc91b5084b9600a93e
push id8456
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:31:52 +0000
treeherdermozilla-aurora@7f2f0fb041b1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1198795
milestone43.0a1
Bug 1198795 - ipc/StructuredCloneUtils should be merged with StructuredCloneHelper, r=smaug
dom/base/PostMessageEvent.cpp
dom/base/StructuredCloneHelper.cpp
dom/base/StructuredCloneHelper.h
dom/base/nsFrameLoader.cpp
dom/base/nsFrameLoader.h
dom/base/nsFrameMessageManager.cpp
dom/base/nsFrameMessageManager.h
dom/base/nsGlobalWindow.cpp
dom/base/nsInProcessTabChildGlobal.cpp
dom/base/nsInProcessTabChildGlobal.h
dom/base/nsStructuredCloneContainer.cpp
dom/broadcastchannel/BroadcastChannel.cpp
dom/broadcastchannel/BroadcastChannelChild.cpp
dom/ipc/ContentBridgeChild.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/StructuredCloneIPCHelper.cpp
dom/ipc/StructuredCloneIPCHelper.h
dom/ipc/StructuredCloneUtils.cpp
dom/ipc/StructuredCloneUtils.h
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/moz.build
dom/ipc/nsIContentChild.cpp
dom/ipc/nsIContentParent.cpp
dom/messagechannel/SharedMessagePortMessage.cpp
dom/messagechannel/SharedMessagePortMessage.h
dom/promise/Promise.cpp
dom/push/PushManager.cpp
dom/workers/DataStore.cpp
dom/workers/ServiceWorkerClient.cpp
dom/workers/ServiceWorkerManager.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/XMLHttpRequest.cpp
widget/gonk/nsClipboard.cpp
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -23,17 +23,18 @@
 namespace mozilla {
 namespace dom {
 
 PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
                                    const nsAString& aCallerOrigin,
                                    nsGlobalWindow* aTargetWindow,
                                    nsIPrincipal* aProvidedPrincipal,
                                    bool aTrustedCaller)
-: StructuredCloneHelper(CloningSupported, TransferringSupported),
+: StructuredCloneHelper(CloningSupported, TransferringSupported,
+                        SameProcessSameThread),
   mSource(aSource),
   mCallerOrigin(aCallerOrigin),
   mTargetWindow(aTargetWindow),
   mProvidedPrincipal(aProvidedPrincipal),
   mTrustedCaller(aTrustedCaller)
 {
   MOZ_COUNT_CTOR(PostMessageEvent);
 }
--- a/dom/base/StructuredCloneHelper.cpp
+++ b/dom/base/StructuredCloneHelper.cpp
@@ -162,17 +162,23 @@ bool
 StructuredCloneHelperInternal::Write(JSContext* aCx,
                                      JS::Handle<JS::Value> aValue,
                                      JS::Handle<JS::Value> aTransfer)
 {
   MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
   MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown.");
 
   mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this);
-  return mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this);
+
+  if (!mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this)) {
+    mBuffer = nullptr;
+    return false;
+  }
+
+  return true;
 }
 
 bool
 StructuredCloneHelperInternal::Read(JSContext* aCx,
                                     JS::MutableHandle<JS::Value> aValue)
 {
   MOZ_ASSERT(mBuffer, "Read() without Write() is not allowed.");
   MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown.");
@@ -212,65 +218,74 @@ StructuredCloneHelperInternal::FreeTrans
                                                     uint64_t aExtraData)
 {
   MOZ_CRASH("Nothing to free.");
 }
 
 // StructuredCloneHelper class
 
 StructuredCloneHelper::StructuredCloneHelper(CloningSupport aSupportsCloning,
-                                             TransferringSupport aSupportsTransferring)
+                                             TransferringSupport aSupportsTransferring,
+                                             ContextSupport aContext)
   : mSupportsCloning(aSupportsCloning == CloningSupported)
   , mSupportsTransferring(aSupportsTransferring == TransferringSupported)
+  , mContext(aContext)
   , mParent(nullptr)
+#ifdef DEBUG
+  , mCreationThread(NS_GetCurrentThread())
+#endif
 {}
 
 StructuredCloneHelper::~StructuredCloneHelper()
 {
   Shutdown();
   MOZ_ASSERT(mTransferredPorts.IsEmpty());
 }
 
 void
 StructuredCloneHelper::Write(JSContext* aCx,
                              JS::Handle<JS::Value> aValue,
-                             bool aMaybeToDifferentThread,
                              ErrorResult& aRv)
 {
-  Write(aCx, aValue, JS::UndefinedHandleValue, aMaybeToDifferentThread, aRv);
+  Write(aCx, aValue, JS::UndefinedHandleValue, aRv);
 }
 
 void
 StructuredCloneHelper::Write(JSContext* aCx,
                              JS::Handle<JS::Value> aValue,
                              JS::Handle<JS::Value> aTransfer,
-                             bool aMaybeToDifferentThread,
                              ErrorResult& aRv)
 {
+  MOZ_ASSERT_IF(mContext == SameProcessSameThread,
+                mCreationThread == NS_GetCurrentThread());
+
   if (!StructuredCloneHelperInternal::Write(aCx, aValue, aTransfer)) {
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
     return;
   }
 
-  if (aMaybeToDifferentThread) {
+  if (mContext != SameProcessSameThread) {
     for (uint32_t i = 0, len = mBlobImplArray.Length(); i < len; ++i) {
       if (!mBlobImplArray[i]->MayBeClonedToOtherThreads()) {
         aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
         return;
       }
     }
   }
 }
 
 void
 StructuredCloneHelper::Read(nsISupports* aParent,
                             JSContext* aCx,
                             JS::MutableHandle<JS::Value> aValue,
                             ErrorResult& aRv)
 {
+  MOZ_ASSERT_IF(mContext == SameProcessSameThread,
+                mCreationThread == NS_GetCurrentThread());
+
   mozilla::AutoRestore<nsISupports*> guard(mParent);
   mParent = aParent;
 
   if (!StructuredCloneHelperInternal::Read(aCx, aValue)) {
     JS_ClearPendingException(aCx);
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
   }
 
@@ -298,16 +313,19 @@ void
 StructuredCloneHelper::ReadFromBuffer(nsISupports* aParent,
                                       JSContext* aCx,
                                       uint64_t* aBuffer,
                                       size_t aBufferLength,
                                       uint32_t aAlgorithmVersion,
                                       JS::MutableHandle<JS::Value> aValue,
                                       ErrorResult& aRv)
 {
+  MOZ_ASSERT_IF(mContext == SameProcessSameThread,
+                mCreationThread == NS_GetCurrentThread());
+
   MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
   MOZ_ASSERT(aBuffer);
 
   mozilla::AutoRestore<nsISupports*> guard(mParent);
   mParent = aParent;
 
   if (!JS_ReadStructuredClone(aCx, aBuffer, aBufferLength, aAlgorithmVersion,
                               aValue, &gCallbacks, this)) {
@@ -315,16 +333,19 @@ StructuredCloneHelper::ReadFromBuffer(ns
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
   }
 }
 
 void
 StructuredCloneHelper::MoveBufferDataToArray(FallibleTArray<uint8_t>& aArray,
                                              ErrorResult& aRv)
 {
+  MOZ_ASSERT_IF(mContext == SameProcessSameThread,
+                mCreationThread == NS_GetCurrentThread());
+
   MOZ_ASSERT(mBuffer, "MoveBuffer() cannot be called without a Write().");
 
   if (NS_WARN_IF(!aArray.SetLength(BufferSize(), mozilla::fallible))) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   uint64_t* buffer;
@@ -714,16 +735,19 @@ StructuredCloneHelper::ReadCallback(JSCo
     return ReadStructuredCloneImageData(aCx, aReader);
   }
 
   if (aTag == SCTAG_DOM_FORMDATA) {
     return ReadFormData(aCx, aReader, aIndex, this);
   }
 
   if (aTag == SCTAG_DOM_IMAGEBITMAP) {
+    MOZ_ASSERT(mContext == SameProcessSameThread ||
+               mContext == SameProcessDifferentThread);
+
      // Get the current global object.
      // This can be null.
      nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(mParent);
      // aIndex is the index of the cloned image.
      return ImageBitmap::ReadStructuredClone(aCx, aReader,
                                              parent, GetImages(), aIndex);
    }
 
@@ -767,17 +791,18 @@ StructuredCloneHelper::WriteCallback(JSC
   {
     nsFormData* formData = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
       return WriteFormData(aWriter, formData, this);
     }
   }
 
   // See if this is an ImageBitmap object.
-  {
+  if (mContext == SameProcessSameThread ||
+      mContext == SameProcessDifferentThread) {
     ImageBitmap* imageBitmap = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) {
       return ImageBitmap::WriteStructuredClone(aWriter,
                                                GetImages(),
                                                imageBitmap);
     }
   }
 
--- a/dom/base/StructuredCloneHelper.h
+++ b/dom/base/StructuredCloneHelper.h
@@ -120,35 +120,45 @@ public:
   };
 
   enum TransferringSupport
   {
     TransferringSupported,
     TransferringNotSupported
   };
 
+  enum ContextSupport
+  {
+    SameProcessSameThread,
+    SameProcessDifferentThread,
+    DifferentProcess
+  };
+
   // If cloning is supported, this object will clone objects such as Blobs,
   // FileList, ImageData, etc.
   // If transferring is supported, we will transfer MessagePorts and in the
   // future other transferrable objects.
+  // The ContextSupport is useful to know where the cloned/transferred data can
+  // be read and written. Additional checks about the nature of the objects
+  // will be done based on this context value because not all the objects can
+  // be sent between threads or processes.
   explicit StructuredCloneHelper(CloningSupport aSupportsCloning,
-                                 TransferringSupport aSupportsTransferring);
+                                 TransferringSupport aSupportsTransferring,
+                                 ContextSupport aContextSupport);
   virtual ~StructuredCloneHelper();
 
   // Normally you should just use Write() and Read().
 
   void Write(JSContext* aCx,
              JS::Handle<JS::Value> aValue,
-             bool aMaybeToDifferentThread,
              ErrorResult &aRv);
 
   void Write(JSContext* aCx,
              JS::Handle<JS::Value> aValue,
              JS::Handle<JS::Value> aTransfer,
-             bool aMaybeToDifferentThread,
              ErrorResult &aRv);
 
   void Read(nsISupports* aParent,
             JSContext* aCx,
             JS::MutableHandle<JS::Value> aValue,
             ErrorResult &aRv);
 
   // Sometimes, when IPC is involved, you must send a buffer after a Write().
@@ -241,19 +251,20 @@ public:
                                      JS::TransferableOwnership* aOwnership,
                                      void** aContent,
                                      uint64_t* aExtraData) override;
 
   virtual void FreeTransferCallback(uint32_t aTag,
                                     JS::TransferableOwnership aOwnership,
                                     void* aContent,
                                     uint64_t aExtraData) override;
-private:
+protected:
   bool mSupportsCloning;
   bool mSupportsTransferring;
+  ContextSupport mContext;
 
   // Useful for the structured clone algorithm:
 
   nsTArray<nsRefPtr<BlobImpl>> mBlobImplArray;
 
   // This is used for sharing the backend of ImageBitmaps.
   // The layers::Image object must be thread-safely reference-counted.
   // The layers::Image object will not be written ever via any ImageBitmap
@@ -267,14 +278,18 @@ private:
   // This array contains the ports once we've finished the reading. It's
   // generated from the mPortIdentifiers array.
   nsTArray<nsRefPtr<MessagePortBase>> 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;
+#endif
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_StructuredCloneHelper_h
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -87,17 +87,17 @@
 #include "nsIAppsService.h"
 #include "GeckoProfiler.h"
 
 #include "jsapi.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "nsSandboxFlags.h"
 #include "mozilla/layers/CompositorChild.h"
 
-#include "mozilla/dom/StructuredCloneUtils.h"
+#include "mozilla/dom/StructuredCloneIPCHelper.h"
 #include "mozilla/WebBrowserPersistLocalDocument.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::hal;
@@ -2406,20 +2406,20 @@ nsFrameLoader::DoLoadMessageManagerScrip
 
 class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase,
                               public nsRunnable
 {
 public:
   nsAsyncMessageToChild(JSContext* aCx,
                         nsFrameLoader* aFrameLoader,
                         const nsAString& aMessage,
-                        const StructuredCloneData& aData,
+                        StructuredCloneIPCHelper& aHelper,
                         JS::Handle<JSObject *> aCpows,
                         nsIPrincipal* aPrincipal)
-    : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
+    : nsSameProcessAsyncMessageBase(aCx, aMessage, aHelper, aCpows, aPrincipal)
     , mFrameLoader(aFrameLoader)
   {
   }
 
   NS_IMETHOD Run()
   {
     nsInProcessTabChildGlobal* tabChild =
       static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
@@ -2431,39 +2431,39 @@ public:
     return NS_OK;
   }
   nsRefPtr<nsFrameLoader> mFrameLoader;
 };
 
 bool
 nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  const StructuredCloneData& aData,
+                                  StructuredCloneIPCHelper& aHelper,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal)
 {
   TabParent* tabParent = mRemoteBrowser;
   if (tabParent) {
     ClonedMessageData data;
     nsIContentParent* cp = tabParent->Manager();
-    if (!BuildClonedMessageDataForParent(cp, aData, data)) {
+    if (!BuildClonedMessageDataForParent(cp, aHelper, data)) {
       return false;
     }
     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
     jsipc::CPOWManager* mgr = cp->GetCPOWManager();
     if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) {
       return false;
     }
     return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows,
                                        IPC::Principal(aPrincipal));
   }
 
   if (mChildMessageManager) {
     nsCOMPtr<nsIRunnable> ev = new nsAsyncMessageToChild(aCx, this, aMessage,
-                                                         aData, aCpows,
+                                                         aHelper, aCpows,
                                                          aPrincipal);
     NS_DispatchToCurrentThread(ev);
     return true;
   }
 
   // We don't have any targets to send our asynchronous message to.
   return false;
 }
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -36,18 +36,18 @@ class nsITabParent;
 class nsIDocShellTreeItem;
 class nsIDocShellTreeOwner;
 class mozIApplication;
 
 namespace mozilla {
 namespace dom {
 class ContentParent;
 class PBrowserParent;
+class StructuredCloneIPCHelper;
 class TabParent;
-struct StructuredCloneData;
 } // namespace dom
 
 namespace layout {
 class RenderFrameParent;
 } // namespace layout
 } // namespace mozilla
 
 #if defined(MOZ_WIDGET_GTK)
@@ -85,17 +85,17 @@ public:
 
   /**
    * MessageManagerCallback methods that we override.
    */
   virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
                                           bool aRunInGlobalScope) override;
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  const mozilla::dom::StructuredCloneData& aData,
+                                  mozilla::dom::StructuredCloneIPCHelper& aHelper,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override;
   virtual bool CheckPermission(const nsAString& aPermission) override;
   virtual bool CheckManifestURL(const nsAString& aManifestURL) override;
   virtual bool CheckAppHasPermission(const nsAString& aPermission) override;
 
   /**
    * Called from the layout frame associated with this frame loader;
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -32,17 +32,17 @@
 #include "mozilla/IntentionalCrash.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/File.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/StructuredCloneUtils.h"
+#include "mozilla/dom/StructuredCloneIPCHelper.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "nsPrintfCString.h"
 #include "nsXULAppAPI.h"
 #include "nsQueryObject.h"
 #include <algorithm>
@@ -271,23 +271,24 @@ struct DataBlobs<Child>
   {
     return aData.blobsChild();
   }
 };
 
 template<ActorFlavorEnum Flavor>
 static bool
 BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
-                       const StructuredCloneData& aData,
+                       StructuredCloneIPCHelper& aHelper,
                        ClonedMessageData& aClonedData)
 {
   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
-  buffer.data = aData.mData;
-  buffer.dataLength = aData.mDataLength;
-  const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = aData.mClosure.mBlobImpls;
+  buffer.data = aHelper.Data();
+  buffer.dataLength = aHelper.DataLength();
+  const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = aHelper.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) {
       typename BlobTraits<Flavor>::BlobType* protocolActor =
         aManager->GetOrCreateActorForBlobImpl(blobImpls[i]);
@@ -297,67 +298,69 @@ BuildClonedMessageData(typename BlobTrai
       blobList.AppendElement(protocolActor);
     }
   }
   return true;
 }
 
 bool
 MessageManagerCallback::BuildClonedMessageDataForParent(nsIContentParent* aParent,
-                                                        const StructuredCloneData& aData,
+                                                        StructuredCloneIPCHelper& aHelper,
                                                         ClonedMessageData& aClonedData)
 {
-  return BuildClonedMessageData<Parent>(aParent, aData, aClonedData);
+  return BuildClonedMessageData<Parent>(aParent, aHelper, aClonedData);
 }
 
 bool
 MessageManagerCallback::BuildClonedMessageDataForChild(nsIContentChild* aChild,
-                                                       const StructuredCloneData& aData,
+                                                       StructuredCloneIPCHelper& aHelper,
                                                        ClonedMessageData& aClonedData)
 {
-  return BuildClonedMessageData<Child>(aChild, aData, aClonedData);
+  return BuildClonedMessageData<Child>(aChild, aHelper, aClonedData);
 }
 
 template<ActorFlavorEnum Flavor>
-static StructuredCloneData
-UnpackClonedMessageData(const ClonedMessageData& aData)
+static void
+UnpackClonedMessageData(const ClonedMessageData& aData,
+                        StructuredCloneIPCHelper& aHelper)
 {
   const SerializedStructuredCloneBuffer& buffer = aData.data();
   typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
   const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aData);
-  StructuredCloneData cloneData;
-  cloneData.mData = buffer.data;
-  cloneData.mDataLength = buffer.dataLength;
+
+  aHelper.UseExternalData(buffer.data, buffer.dataLength);
+
   if (!blobs.IsEmpty()) {
     uint32_t length = blobs.Length();
-    cloneData.mClosure.mBlobImpls.SetCapacity(length);
+    aHelper.BlobImpls().SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       auto* blob =
         static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
       MOZ_ASSERT(blob);
 
       nsRefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
       MOZ_ASSERT(blobImpl);
 
-      cloneData.mClosure.mBlobImpls.AppendElement(blobImpl);
+      aHelper.BlobImpls().AppendElement(blobImpl);
     }
   }
-  return cloneData;
 }
 
-StructuredCloneData
-mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aData)
+void
+mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aData,
+                                                    StructuredCloneIPCHelper& aHelper)
 {
-  return UnpackClonedMessageData<Parent>(aData);
+  UnpackClonedMessageData<Parent>(aData, aHelper);
 }
 
-StructuredCloneData
-mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aData)
+void
+mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aData,
+                                                   StructuredCloneIPCHelper& aHelper)
 {
-  return UnpackClonedMessageData<Child>(aData);
+  UnpackClonedMessageData<Child>(aData, aHelper);
 }
 
 bool
 SameProcessCpowHolder::ToObject(JSContext* aCx,
                                 JS::MutableHandle<JSObject*> aObjp)
 {
   if (!mObj) {
     return true;
@@ -645,24 +648,27 @@ 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& aData,
-                    JSAutoStructuredCloneBuffer& aBuffer,
-                    StructuredCloneClosure& aClosure)
+                    StructuredCloneIPCHelper& aHelper)
 {
   // First try to use structured clone on the whole thing.
   JS::RootedValue v(aCx, aData);
-  if (WriteStructuredClone(aCx, v, aBuffer, aClosure)) {
+  ErrorResult rv;
+  aHelper.Write(aCx, v, rv);
+  if (!rv.Failed()) {
     return true;
   }
+
+  rv.SuppressException();
   JS_ClearPendingException(aCx);
 
   nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   if (console) {
     nsAutoString filename;
     uint32_t lineno = 0, column = 0;
     nsJSUtils::GetCallingLocation(aCx, filename, &lineno, &column);
     nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
@@ -680,17 +686,23 @@ GetParamsForMessage(JSContext* aCx,
   NS_ENSURE_TRUE(JS_Stringify(aCx, &v, nullptr, JS::NullHandleValue,
                               JSONCreator, &json), false);
   NS_ENSURE_TRUE(!json.IsEmpty(), false);
 
   JS::Rooted<JS::Value> val(aCx, JS::NullValue());
   NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const char16_t*>(json.get()),
                               json.Length(), &val), false);
 
-  return WriteStructuredClone(aCx, val, aBuffer, aClosure);
+  aHelper.Write(aCx, val, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    rv.SuppressException();
+    return false;
+  }
+
+  return true;
 }
 
 
 // nsISyncMessageSender
 
 static bool sSendingSyncMessage = false;
 
 NS_IMETHODIMP
@@ -736,40 +748,36 @@ nsFrameMessageManager::SendMessage(const
   aRetval.setUndefined();
   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;
-  JSAutoStructuredCloneBuffer buffer;
-  if (aArgc >= 2 &&
-      !GetParamsForMessage(aCx, aJSON, buffer, data.mClosure)) {
+  StructuredCloneIPCHelper helper;
+  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, helper)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
-  data.mData = buffer.data();
-  data.mDataLength = buffer.nbytes();
 
   JS::Rooted<JSObject*> objects(aCx);
   if (aArgc >= 3 && aObjects.isObject()) {
     objects = &aObjects.toObject();
   }
 
   nsTArray<OwningSerializedStructuredCloneBuffer> retval;
 
   sSendingSyncMessage |= aIsSync;
-  bool rv = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects,
+  bool ok = mCallback->DoSendBlockingMessage(aCx, aMessageName, helper, objects,
                                              aPrincipal, &retval, aIsSync);
   if (aIsSync) {
     sSendingSyncMessage = false;
   }
 
-  if (!rv) {
+  if (!ok) {
     return NS_OK;
   }
 
   uint32_t len = retval.Length();
   JS::Rooted<JSObject*> dataArray(aCx, JS_NewArrayObject(aCx, len));
   NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
 
   for (uint32_t i = 0; i < len; ++i) {
@@ -786,64 +794,58 @@ nsFrameMessageManager::SendMessage(const
 
   aRetval.setObject(*dataArray);
   return NS_OK;
 }
 
 nsresult
 nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx,
                                                     const nsAString& aMessage,
-                                                    const StructuredCloneData& aData,
+                                                    StructuredCloneIPCHelper& aHelper,
                                                     JS::Handle<JSObject *> aCpows,
                                                     nsIPrincipal* aPrincipal)
 {
   if (mIsBroadcaster) {
     int32_t len = mChildManagers.Count();
     for (int32_t i = 0; i < len; ++i) {
       static_cast<nsFrameMessageManager*>(mChildManagers[i])->
-         DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows, aPrincipal);
+         DispatchAsyncMessageInternal(aCx, aMessage, aHelper, aCpows, aPrincipal);
     }
     return NS_OK;
   }
 
   if (!mCallback) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
-  if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal)) {
+  if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aHelper, aCpows, aPrincipal)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 nsresult
 nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
                                             const JS::Value& aJSON,
                                             const JS::Value& aObjects,
                                             nsIPrincipal* aPrincipal,
                                             JSContext* aCx,
                                             uint8_t aArgc)
 {
-  StructuredCloneData data;
-  JSAutoStructuredCloneBuffer buffer;
-
-  if (aArgc >= 2 &&
-      !GetParamsForMessage(aCx, aJSON, buffer, data.mClosure)) {
+  StructuredCloneIPCHelper helper;
+  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, helper)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   JS::Rooted<JSObject*> objects(aCx);
   if (aArgc >= 3 && aObjects.isObject()) {
     objects = &aObjects.toObject();
   }
 
-  data.mData = buffer.data();
-  data.mDataLength = buffer.nbytes();
-
-  return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects,
+  return DispatchAsyncMessageInternal(aCx, aMessageName, helper, objects,
                                       aPrincipal);
 }
 
 
 // nsIMessageSender
 
 NS_IMETHODIMP
 nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
@@ -1062,32 +1064,32 @@ public:
 
 // nsIMessageListener
 
 nsresult
 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
                                       nsIFrameLoader* aTargetFrameLoader,
                                       const nsAString& aMessage,
                                       bool aIsSync,
-                                      const StructuredCloneData* aCloneData,
+                                      StructuredCloneIPCHelper* aCloneHelper,
                                       mozilla::jsipc::CpowHolder* aCpows,
                                       nsIPrincipal* aPrincipal,
                                       nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal)
 {
   return ReceiveMessage(aTarget, aTargetFrameLoader, mClosed, aMessage, aIsSync,
-                        aCloneData, aCpows, aPrincipal, aRetVal);
+                        aCloneHelper, aCpows, aPrincipal, aRetVal);
 }
 
 nsresult
 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
                                       nsIFrameLoader* aTargetFrameLoader,
                                       bool aTargetClosed,
                                       const nsAString& aMessage,
                                       bool aIsSync,
-                                      const StructuredCloneData* aCloneData,
+                                      StructuredCloneIPCHelper* aCloneHelper,
                                       mozilla::jsipc::CpowHolder* aCpows,
                                       nsIPrincipal* aPrincipal,
                                       nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal)
 {
   nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
     mListeners.Get(aMessage);
   if (listeners) {
 
@@ -1161,20 +1163,24 @@ nsFrameMessageManager::ReceiveMessage(ns
         if (!cpows) {
           return NS_ERROR_UNEXPECTED;
         }
       }
 
       JS::Rooted<JS::Value> cpowsv(cx, JS::ObjectValue(*cpows));
 
       JS::Rooted<JS::Value> json(cx, JS::NullValue());
-      if (aCloneData && aCloneData->mDataLength &&
-          !ReadStructuredClone(cx, *aCloneData, &json)) {
-        JS_ClearPendingException(cx);
-        return NS_OK;
+      if (aCloneHelper && aCloneHelper->DataLength()) {
+        ErrorResult rv;
+        aCloneHelper->Read(cx, &json, rv);
+        if (NS_WARN_IF(rv.Failed())) {
+          rv.SuppressException();
+          JS_ClearPendingException(cx);
+          return NS_OK;
+        }
       }
       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) &&
@@ -1280,17 +1286,17 @@ nsFrameMessageManager::ReceiveMessage(ns
           buffer.steal(&data->data, &data->dataLength);
         }
       }
     }
   }
   nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
   return mParentManager ? mParentManager->ReceiveMessage(aTarget, aTargetFrameLoader,
                                                          aTargetClosed, aMessage,
-                                                         aIsSync, aCloneData,
+                                                         aIsSync, aCloneHelper,
                                                          aCpows, aPrincipal,
                                                          aRetVal) : NS_OK;
 }
 
 void
 nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager)
 {
   mChildManagers.AppendObject(aManager);
@@ -1884,20 +1890,20 @@ nsFrameMessageManager* nsFrameMessageMan
 nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
 
 class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase,
                                          public nsRunnable
 {
 public:
   nsAsyncMessageToSameProcessChild(JSContext* aCx,
                                    const nsAString& aMessage,
-                                   const StructuredCloneData& aData,
+                                   StructuredCloneIPCHelper& aHelper,
                                    JS::Handle<JSObject *> aCpows,
                                    nsIPrincipal* aPrincipal)
-    : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
+    : nsSameProcessAsyncMessageBase(aCx, aMessage, aHelper, aCpows, aPrincipal)
   {
   }
 
   NS_IMETHOD Run()
   {
     nsFrameMessageManager* ppm = nsFrameMessageManager::GetChildProcessManager();
     ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), nullptr, ppm);
     return NS_OK;
@@ -1926,22 +1932,22 @@ public:
     ProcessGlobal* global = ProcessGlobal::Get();
     MOZ_ASSERT(!aRunInGlobalScope);
     global->LoadScript(aURL);
     return true;
   }
 
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  const StructuredCloneData& aData,
+                                  StructuredCloneIPCHelper& aHelper,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override
   {
     nsCOMPtr<nsIRunnable> ev =
-      new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows,
+      new nsAsyncMessageToSameProcessChild(aCx, aMessage, aHelper, aCpows,
                                            aPrincipal);
     NS_DispatchToCurrentThread(ev);
     return true;
   }
 
   bool CheckPermission(const nsAString& aPermission) override
   {
     // In a single-process scenario, the child always has all capabilities.
@@ -1980,56 +1986,56 @@ public:
   }
   virtual ~ChildProcessMessageManagerCallback()
   {
     MOZ_COUNT_DTOR(ChildProcessMessageManagerCallback);
   }
 
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                      const nsAString& aMessage,
-                                     const mozilla::dom::StructuredCloneData& aData,
+                                     StructuredCloneIPCHelper& aHelper,
                                      JS::Handle<JSObject *> aCpows,
                                      nsIPrincipal* aPrincipal,
                                      nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal,
                                      bool aIsSync) override
   {
     mozilla::dom::ContentChild* cc =
       mozilla::dom::ContentChild::GetSingleton();
     if (!cc) {
       return true;
     }
     ClonedMessageData data;
-    if (!BuildClonedMessageDataForChild(cc, aData, data)) {
+    if (!BuildClonedMessageDataForChild(cc, aHelper, data)) {
       return false;
     }
     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
     if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
       return false;
     }
     if (aIsSync) {
       return cc->SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
                                  IPC::Principal(aPrincipal), aRetVal);
     }
     return cc->SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
                               IPC::Principal(aPrincipal), aRetVal);
   }
 
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  const mozilla::dom::StructuredCloneData& aData,
+                                  StructuredCloneIPCHelper& aHelper,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override
   {
     mozilla::dom::ContentChild* cc =
       mozilla::dom::ContentChild::GetSingleton();
     if (!cc) {
       return true;
     }
     ClonedMessageData data;
-    if (!BuildClonedMessageDataForChild(cc, aData, data)) {
+    if (!BuildClonedMessageDataForChild(cc, aHelper, data)) {
       return false;
     }
     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
     if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
       return false;
     }
     return cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
                                 IPC::Principal(aPrincipal));
@@ -2039,20 +2045,20 @@ public:
 
 
 class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase,
                                           public SameProcessMessageQueue::Runnable
 {
 public:
   nsAsyncMessageToSameProcessParent(JSContext* aCx,
                                     const nsAString& aMessage,
-                                    const StructuredCloneData& aData,
+                                    StructuredCloneIPCHelper& aHelper,
                                     JS::Handle<JSObject *> aCpows,
                                     nsIPrincipal* aPrincipal)
-    : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
+    : nsSameProcessAsyncMessageBase(aCx, aMessage, aHelper, aCpows, aPrincipal)
   {
   }
 
   virtual nsresult HandleMessage() override
   {
     nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager;
     ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), nullptr, ppm);
     return NS_OK;
@@ -2071,43 +2077,43 @@ public:
   }
   virtual ~SameChildProcessMessageManagerCallback()
   {
     MOZ_COUNT_DTOR(SameChildProcessMessageManagerCallback);
   }
 
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                      const nsAString& aMessage,
-                                     const mozilla::dom::StructuredCloneData& aData,
+                                     StructuredCloneIPCHelper& aHelper,
                                      JS::Handle<JSObject *> aCpows,
                                      nsIPrincipal* aPrincipal,
                                      nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal,
                                      bool aIsSync) override
   {
     SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
     queue->Flush();
 
     if (nsFrameMessageManager::sSameProcessParentManager) {
       SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
       nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr, aMessage,
-                          true, &aData, &cpows, aPrincipal, aRetVal);
+                          true, &aHelper, &cpows, aPrincipal, aRetVal);
     }
     return true;
   }
 
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  const mozilla::dom::StructuredCloneData& aData,
+                                  StructuredCloneIPCHelper& aHelper,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override
   {
     SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
     nsRefPtr<nsAsyncMessageToSameProcessParent> ev =
-      new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows, aPrincipal);
+      new nsAsyncMessageToSameProcessParent(aCx, aMessage, aHelper, aCpows, aPrincipal);
     queue->Push(ev);
     return true;
   }
 
 };
 
 
 // This creates the global parent process message manager.
@@ -2197,44 +2203,38 @@ nsFrameMessageManager::MarkForCC()
   if (mRefCnt.IsPurple()) {
     mRefCnt.RemovePurple();
   }
   return true;
 }
 
 nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx,
                                                              const nsAString& aMessage,
-                                                             const StructuredCloneData& aData,
+                                                             StructuredCloneIPCHelper& aHelper,
                                                              JS::Handle<JSObject*> aCpows,
                                                              nsIPrincipal* aPrincipal)
   : mRuntime(js::GetRuntime(aCx)),
     mMessage(aMessage),
     mCpows(aCx, aCpows),
     mPrincipal(aPrincipal)
 {
-  if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
+  if (!mHelper.Copy(aHelper)) {
 #ifdef MOZ_CRASHREPORTER
     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncMessageOOM"),
                                        NS_ConvertUTF16toUTF8(aMessage));
 #endif
-    NS_ABORT_OOM(aData.mDataLength);
+    NS_ABORT_OOM(aHelper.DataLength());
   }
-  mClosure = aData.mClosure;
 }
 
 void
 nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget,
                                               nsIFrameLoader* aTargetFrameLoader,
                                               nsFrameMessageManager* aManager)
 {
   if (aManager) {
-    StructuredCloneData data;
-    data.mData = mData.data();
-    data.mDataLength = mData.nbytes();
-    data.mClosure = mClosure;
-
     SameProcessCpowHolder cpows(mRuntime, mCpows);
 
     nsRefPtr<nsFrameMessageManager> mm = aManager;
-    mm->ReceiveMessage(aTarget, aTargetFrameLoader, mMessage, false, &data, &cpows,
-                       mPrincipal, nullptr);
+    mm->ReceiveMessage(aTarget, aTargetFrameLoader, mMessage, false, &mHelper,
+                       &cpows, mPrincipal, nullptr);
   }
 }
--- a/dom/base/nsFrameMessageManager.h
+++ b/dom/base/nsFrameMessageManager.h
@@ -23,17 +23,17 @@
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "nsThreadUtils.h"
 #include "nsWeakPtr.h"
 #include "mozilla/Attributes.h"
 #include "js/RootingAPI.h"
 #include "nsTObserverArray.h"
 #include "mozilla/dom/SameProcessMessageQueue.h"
-#include "mozilla/dom/StructuredCloneUtils.h"
+#include "mozilla/dom/StructuredCloneIPCHelper.h"
 #include "mozilla/jsipc/CpowHolder.h"
 
 class nsIFrameLoader;
 
 namespace mozilla {
 
 struct OwningSerializedStructuredCloneBuffer;
 
@@ -65,28 +65,28 @@ public:
 
   virtual bool DoLoadMessageManagerScript(const nsAString& aURL, bool aRunInGlobalScope)
   {
     return true;
   }
 
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                      const nsAString& aMessage,
-                                     const StructuredCloneData& aData,
+                                     StructuredCloneIPCHelper& aHelper,
                                      JS::Handle<JSObject*> aCpows,
                                      nsIPrincipal* aPrincipal,
                                      nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal,
                                      bool aIsSync)
   {
     return true;
   }
 
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  const StructuredCloneData& aData,
+                                  StructuredCloneIPCHelper& aHelper,
                                   JS::Handle<JSObject*> aCpows,
                                   nsIPrincipal* aPrincipal)
   {
     return true;
   }
 
   virtual bool CheckPermission(const nsAString& aPermission)
   {
@@ -111,25 +111,28 @@ public:
   virtual bool KillChild()
   {
     // By default, does nothing.
     return false;
   }
 
 protected:
   bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
-                                       const StructuredCloneData& aData,
+                                       StructuredCloneIPCHelper& aHelper,
                                        ClonedMessageData& aClonedData);
   bool BuildClonedMessageDataForChild(nsIContentChild* aChild,
-                                      const StructuredCloneData& aData,
+                                      StructuredCloneIPCHelper& aHelper,
                                       ClonedMessageData& aClonedData);
 };
 
-StructuredCloneData UnpackClonedMessageDataForParent(const ClonedMessageData& aData);
-StructuredCloneData UnpackClonedMessageDataForChild(const ClonedMessageData& aData);
+void UnpackClonedMessageDataForParent(const ClonedMessageData& aData,
+                                      StructuredCloneIPCHelper& aHelper);
+
+void UnpackClonedMessageDataForChild(const ClonedMessageData& aData,
+                                     StructuredCloneIPCHelper& aHelper);
 
 } // namespace ipc
 } // namespace dom
 } // namespace mozilla
 
 struct nsMessageListenerInfo
 {
   bool operator==(const nsMessageListenerInfo& aOther) const
@@ -161,17 +164,17 @@ private:
 
 class nsFrameMessageManager final : public nsIContentFrameMessageManager,
                                     public nsIMessageBroadcaster,
                                     public nsIFrameScriptLoader,
                                     public nsIGlobalProcessScriptLoader,
                                     public nsIProcessChecker
 {
   friend class mozilla::dom::MessageManagerReporter;
-  typedef mozilla::dom::StructuredCloneData StructuredCloneData;
+  typedef mozilla::dom::StructuredCloneIPCHelper StructuredCloneIPCHelper;
   typedef mozilla::OwningSerializedStructuredCloneBuffer OwningSerializedStructuredCloneBuffer;
 public:
   nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
                         nsFrameMessageManager* aParentManager,
                         /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags);
 
 private:
   ~nsFrameMessageManager();
@@ -191,17 +194,17 @@ public:
   NS_DECL_NSIGLOBALPROCESSSCRIPTLOADER
   NS_DECL_NSIPROCESSCHECKER
 
   static nsFrameMessageManager*
   NewProcessMessageManager(bool aIsRemote);
 
   nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
                           const nsAString& aMessage,
-                          bool aIsSync, const StructuredCloneData* aCloneData,
+                          bool aIsSync, StructuredCloneIPCHelper* aCloneHelper,
                           mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
                           nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal);
 
   void AddChildManager(nsFrameMessageManager* aManager);
   void RemoveChildManager(nsFrameMessageManager* aManager)
   {
     mChildManagers.RemoveObject(aManager);
   }
@@ -218,17 +221,17 @@ public:
   nsresult DispatchAsyncMessage(const nsAString& aMessageName,
                                 const JS::Value& aJSON,
                                 const JS::Value& aObjects,
                                 nsIPrincipal* aPrincipal,
                                 JSContext* aCx,
                                 uint8_t aArgc);
   nsresult DispatchAsyncMessageInternal(JSContext* aCx,
                                         const nsAString& aMessage,
-                                        const StructuredCloneData& aData,
+                                        StructuredCloneIPCHelper& aHelper,
                                         JS::Handle<JSObject*> aCpows,
                                         nsIPrincipal* aPrincipal);
   void RemoveFromParent();
   nsFrameMessageManager* GetParentManager() { return mParentManager; }
   void SetParentManager(nsFrameMessageManager* aParent)
   {
     NS_ASSERTION(!mParentManager, "We have parent manager already!");
     NS_ASSERTION(mChrome, "Should not set parent manager!");
@@ -259,17 +262,17 @@ private:
                        nsIPrincipal* aPrincipal,
                        JSContext* aCx,
                        uint8_t aArgc,
                        JS::MutableHandle<JS::Value> aRetval,
                        bool aIsSync);
 
   nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
                           bool aTargetClosed, const nsAString& aMessage,
-                          bool aIsSync, const StructuredCloneData* aCloneData,
+                          bool aIsSync, StructuredCloneIPCHelper* aCloneHelper,
                           mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
                           nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal);
 
   NS_IMETHOD LoadScript(const nsAString& aURL,
                         bool aAllowDelayedLoad,
                         bool aRunInGlobalScope);
   NS_IMETHOD RemoveDelayedScript(const nsAString& aURL);
   NS_IMETHOD GetDelayedScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList);
@@ -324,37 +327,34 @@ private:
      NS_IMETHOD Run() {
        ReceiveMessage(..., ...);
        return NS_OK;
      }
    };
  */
 class nsSameProcessAsyncMessageBase
 {
-  typedef mozilla::dom::StructuredCloneClosure StructuredCloneClosure;
-
 public:
-  typedef mozilla::dom::StructuredCloneData StructuredCloneData;
+  typedef mozilla::dom::StructuredCloneIPCHelper StructuredCloneIPCHelper;
 
   nsSameProcessAsyncMessageBase(JSContext* aCx,
                                 const nsAString& aMessage,
-                                const StructuredCloneData& aData,
+                                StructuredCloneIPCHelper& aHelper,
                                 JS::Handle<JSObject*> aCpows,
                                 nsIPrincipal* aPrincipal);
 
   void ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
                       nsFrameMessageManager* aManager);
 
 private:
   nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
 
   JSRuntime* mRuntime;
   nsString mMessage;
-  JSAutoStructuredCloneBuffer mData;
-  StructuredCloneClosure mClosure;
+  StructuredCloneIPCHelper mHelper;
   JS::PersistentRooted<JSObject*> mCpows;
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 class nsScriptCacheCleaner;
 
 struct nsMessageManagerScriptHolder
 {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8647,17 +8647,17 @@ nsGlobalWindow::PostMessageMozOuter(JSCo
                          origin,
                          this,
                          providedPrincipal,
                          nsContentUtils::IsCallerChrome());
 
   JS::Rooted<JS::Value> message(aCx, aMessage);
   JS::Rooted<JS::Value> transfer(aCx, aTransfer);
 
-  event->Write(aCx, message, transfer, false, aError);
+  event->Write(aCx, message, transfer, aError);
   if (NS_WARN_IF(aError.Failed())) {
     return;
   }
 
   aError = NS_DispatchToCurrentThread(event);
 }
 
 void
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -13,80 +13,76 @@
 #include "nsComponentManagerUtils.h"
 #include "nsScriptLoader.h"
 #include "nsFrameLoader.h"
 #include "xpcpublic.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsDOMClassInfoID.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/SameProcessMessageQueue.h"
-#include "mozilla/dom/StructuredCloneUtils.h"
-#include "js/StructuredClone.h"
 
-using mozilla::dom::StructuredCloneData;
-using mozilla::dom::StructuredCloneClosure;
 using namespace mozilla;
 using namespace mozilla::dom;
 
 bool
 nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx,
                                                  const nsAString& aMessage,
-                                                 const dom::StructuredCloneData& aData,
+                                                 StructuredCloneIPCHelper& aHelper,
                                                  JS::Handle<JSObject *> aCpows,
                                                  nsIPrincipal* aPrincipal,
                                                  nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal,
                                                  bool aIsSync)
 {
   SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
   queue->Flush();
 
   if (mChromeMessageManager) {
     SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
     nsRefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
     nsCOMPtr<nsIFrameLoader> fl = GetFrameLoader();
-    mm->ReceiveMessage(mOwner, fl, aMessage, true, &aData, &cpows, aPrincipal,
+    mm->ReceiveMessage(mOwner, fl, aMessage, true, &aHelper, &cpows, aPrincipal,
                        aRetVal);
   }
   return true;
 }
 
 class nsAsyncMessageToParent : public nsSameProcessAsyncMessageBase,
                                public SameProcessMessageQueue::Runnable
 {
 public:
   nsAsyncMessageToParent(JSContext* aCx,
                          nsInProcessTabChildGlobal* aTabChild,
                          const nsAString& aMessage,
-                         const StructuredCloneData& aData,
+                         StructuredCloneIPCHelper& aHelper,
                          JS::Handle<JSObject *> aCpows,
                          nsIPrincipal* aPrincipal)
-    : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal),
+    : nsSameProcessAsyncMessageBase(aCx, aMessage, aHelper, aCpows, aPrincipal),
       mTabChild(aTabChild)
   {
   }
 
   virtual nsresult HandleMessage() override
   {
     nsCOMPtr<nsIFrameLoader> fl = mTabChild->GetFrameLoader();
     ReceiveMessage(mTabChild->mOwner, fl, mTabChild->mChromeMessageManager);
     return NS_OK;
   }
   nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
 };
 
 bool
 nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx,
                                               const nsAString& aMessage,
-                                              const StructuredCloneData& aData,
+                                              StructuredCloneIPCHelper& aHelper,
                                               JS::Handle<JSObject *> aCpows,
                                               nsIPrincipal* aPrincipal)
 {
   SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
   nsRefPtr<nsAsyncMessageToParent> ev =
-    new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows, aPrincipal);
+    new nsAsyncMessageToParent(aCx, this, aMessage, aHelper, aCpows, aPrincipal);
   queue->Push(ev);
   return true;
 }
 
 nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
                                                      nsIContent* aOwner,
                                                      nsFrameMessageManager* aChrome)
 : mDocShell(aShell), mInitialized(false), mLoadingScript(false),
--- a/dom/base/nsInProcessTabChildGlobal.h
+++ b/dom/base/nsInProcessTabChildGlobal.h
@@ -78,24 +78,24 @@ public:
 
   NS_DECL_NSIINPROCESSCONTENTFRAMEMESSAGEMANAGER
 
   /**
    * MessageManagerCallback methods that we override.
    */
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                       const nsAString& aMessage,
-                                      const mozilla::dom::StructuredCloneData& aData,
+                                      mozilla::dom::StructuredCloneIPCHelper& aHelper,
                                       JS::Handle<JSObject *> aCpows,
                                       nsIPrincipal* aPrincipal,
                                       nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal,
                                       bool aIsSync) override;
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  const mozilla::dom::StructuredCloneData& aData,
+                                  mozilla::dom::StructuredCloneIPCHelper& aHelper,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override;
 
   virtual nsresult PreHandleEvent(
                      mozilla::EventChainPreVisitor& aVisitor) override;
   NS_IMETHOD AddEventListener(const nsAString& aType,
                               nsIDOMEventListener* aListener,
                               bool aUseCapture)
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -26,17 +26,18 @@ NS_IMPL_ADDREF(nsStructuredCloneContaine
 NS_IMPL_RELEASE(nsStructuredCloneContainer)
 
 NS_INTERFACE_MAP_BEGIN(nsStructuredCloneContainer)
   NS_INTERFACE_MAP_ENTRY(nsIStructuredCloneContainer)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 nsStructuredCloneContainer::nsStructuredCloneContainer()
-  : StructuredCloneHelper(CloningSupported, TransferringNotSupported)
+  : StructuredCloneHelper(CloningSupported, TransferringNotSupported,
+                          DifferentProcess)
   , mState(eNotInitialized) , mData(nullptr), mSize(0), mVersion(0)
 {
 }
 
 nsStructuredCloneContainer::~nsStructuredCloneContainer()
 {
   if (mData) {
     free(mData);
@@ -47,17 +48,17 @@ NS_IMETHODIMP
 nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData,
                                           JSContext* aCx)
 {
   if (mState != eNotInitialized) {
     return NS_ERROR_FAILURE;
   }
 
   ErrorResult rv;
-  Write(aCx, aData, true, rv);
+  Write(aCx, aData, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
   mState = eInitializedFromJSVal;
   return NS_OK;
 }
 
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -32,17 +32,18 @@ namespace dom {
 using namespace workers;
 
 class BroadcastChannelMessage final : public StructuredCloneHelper
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(BroadcastChannelMessage)
 
   BroadcastChannelMessage()
-    : StructuredCloneHelper(CloningSupported, TransferringNotSupported)
+    : StructuredCloneHelper(CloningSupported, TransferringNotSupported,
+                            DifferentProcess)
   {}
 
 private:
   ~BroadcastChannelMessage()
   {}
 };
 
 namespace {
@@ -449,17 +450,17 @@ BroadcastChannel::PostMessage(JSContext*
 
 void
 BroadcastChannel::PostMessageInternal(JSContext* aCx,
                                       JS::Handle<JS::Value> aMessage,
                                       ErrorResult& aRv)
 {
   nsRefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
 
-  data->Write(aCx, aMessage, true, aRv);
+  data->Write(aCx, aMessage, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   PostMessageData(data);
 }
 
 void
--- a/dom/broadcastchannel/BroadcastChannelChild.cpp
+++ b/dom/broadcastchannel/BroadcastChannelChild.cpp
@@ -83,17 +83,18 @@ BroadcastChannelChild::RecvNotify(const 
   if (!globalObject || !jsapi.Init(globalObject)) {
     NS_WARNING("Failed to initialize AutoJSAPI object.");
     return true;
   }
 
   JSContext* cx = jsapi.cx();
   const SerializedStructuredCloneBuffer& buffer = aData.data();
   StructuredCloneHelper cloneHelper(StructuredCloneHelper::CloningSupported,
-                                    StructuredCloneHelper::TransferringNotSupported);
+                                    StructuredCloneHelper::TransferringNotSupported,
+                                    StructuredCloneHelper::DifferentProcess);
 
   cloneHelper.BlobImpls().AppendElements(blobs);
 
   JS::Rooted<JS::Value> value(cx, JS::NullValue());
   if (buffer.dataLength) {
     ErrorResult rv;
     cloneHelper.ReadFromBuffer(mBC->GetParentObject(), cx,
                                buffer.data, buffer.dataLength, &value, rv);
--- a/dom/ipc/ContentBridgeChild.cpp
+++ b/dom/ipc/ContentBridgeChild.cpp
@@ -2,17 +2,16 @@
 /* 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 "mozilla/dom/ContentBridgeChild.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/File.h"
-#include "mozilla/dom/StructuredCloneUtils.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 
 using namespace mozilla::ipc;
 using namespace mozilla::jsipc;
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -173,17 +173,17 @@
 #include "mozilla/dom/PresentationIPCService.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/PSpeechSynthesisChild.h"
 #endif
 
 #include "ProcessUtils.h"
-#include "StructuredCloneUtils.h"
+#include "StructuredCloneIPCHelper.h"
 #include "URIUtils.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 #include "nsDeviceStorage.h"
 #include "DomainPolicy.h"
 #include "mozilla/dom/DataStoreService.h"
 #include "mozilla/dom/telephony/PTelephonyChild.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
@@ -2077,20 +2077,21 @@ ContentChild::RecvLoadProcessScript(cons
 bool
 ContentChild::RecvAsyncMessage(const nsString& aMsg,
                                const ClonedMessageData& aData,
                                InfallibleTArray<CpowEntry>&& aCpows,
                                const IPC::Principal& aPrincipal)
 {
     nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::GetChildProcessManager();
     if (cpm) {
-        StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
+        StructuredCloneIPCHelper helper;
+        ipc::UnpackClonedMessageDataForChild(aData, helper);
         CrossProcessCpowHolder cpows(this, aCpows);
         cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()), nullptr,
-                            aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
+                            aMsg, false, &helper, &cpows, aPrincipal, nullptr);
     }
     return true;
 }
 
 bool
 ContentChild::RecvGeolocationUpdate(const GeoPosition& somewhere)
 {
     nsCOMPtr<nsIGeolocationUpdate> gs = do_GetService("@mozilla.org/geolocation/service;1");
@@ -2862,9 +2863,8 @@ ContentChild::RecvTestGraphicsDeviceRese
 #if defined(XP_WIN)
   gfxPlatform::GetPlatform()->TestDeviceReset(DeviceResetReason(aResetReason));
 #endif
   return true;
 }
 
 } // namespace dom
 } // namespace mozilla
-
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -148,17 +148,17 @@
 #include "nsThreadUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsWidgetsCID.h"
 #include "PreallocatedProcessManager.h"
 #include "ProcessPriorityManager.h"
 #include "SandboxHal.h"
 #include "ScreenManagerParent.h"
 #include "SourceSurfaceRawData.h"
-#include "StructuredCloneUtils.h"
+#include "StructuredCloneIPCHelper.h"
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
 #include "nsDocShell.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "gfxPrefs.h"
 #include "prio.h"
@@ -4450,22 +4450,22 @@ ContentParent::DoLoadMessageManagerScrip
 {
     MOZ_ASSERT(!aRunInGlobalScope);
     return SendLoadProcessScript(nsString(aURL));
 }
 
 bool
 ContentParent::DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  const mozilla::dom::StructuredCloneData& aData,
+                                  StructuredCloneIPCHelper& aHelper,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal)
 {
     ClonedMessageData data;
-    if (!BuildClonedMessageDataForParent(this, aData, data)) {
+    if (!BuildClonedMessageDataForParent(this, aHelper, data)) {
         return false;
     }
     InfallibleTArray<CpowEntry> cpows;
     jsipc::CPOWManager* mgr = GetCPOWManager();
     if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) {
         return false;
     }
 #ifdef MOZ_NUWA_PROCESS
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -197,17 +197,17 @@ public:
 
     /**
      * MessageManagerCallback methods that we override.
      */
     virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
                                             bool aRunInGlobalScope) override;
     virtual bool DoSendAsyncMessage(JSContext* aCx,
                                     const nsAString& aMessage,
-                                    const mozilla::dom::StructuredCloneData& aData,
+                                    mozilla::dom::StructuredCloneIPCHelper& aHelper,
                                     JS::Handle<JSObject *> aCpows,
                                     nsIPrincipal* aPrincipal) override;
     virtual bool CheckPermission(const nsAString& aPermission) override;
     virtual bool CheckManifestURL(const nsAString& aManifestURL) override;
     virtual bool CheckAppHasPermission(const nsAString& aPermission) override;
     virtual bool CheckAppHasStatus(unsigned short aStatus) override;
     virtual bool KillChild() override;
 
rename from dom/ipc/StructuredCloneUtils.cpp
rename to dom/ipc/StructuredCloneIPCHelper.cpp
--- a/dom/ipc/StructuredCloneUtils.cpp
+++ b/dom/ipc/StructuredCloneIPCHelper.cpp
@@ -1,140 +1,83 @@
 /* -*- 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 "StructuredCloneUtils.h"
+#include "StructuredCloneIPCHelper.h"
 
 #include "nsIDOMDOMException.h"
 #include "nsIMutable.h"
 #include "nsIXPConnect.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "nsContentUtils.h"
 #include "nsJSEnvironment.h"
 #include "MainThreadUtils.h"
 #include "StructuredCloneTags.h"
 #include "jsapi.h"
 
-using namespace mozilla::dom;
-
-namespace {
-
-void
-Error(JSContext* aCx, uint32_t aErrorId)
-{
-  if (NS_IsMainThread()) {
-    NS_DOMStructuredCloneError(aCx, aErrorId);
-  } else {
-    Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
-  }
-}
-
-JSObject*
-Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
-     uint32_t aData, void* aClosure)
-{
-  MOZ_ASSERT(aClosure);
-
-  StructuredCloneClosure* closure =
-    static_cast<StructuredCloneClosure*>(aClosure);
-
-  if (aTag == SCTAG_DOM_BLOB) {
-    // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
-    // called because the static analysis thinks dereferencing XPCOM objects
-    // can GC (because in some cases it can!), and a return statement with a
-    // JSObject* type means that JSObject* is on the stack as a raw pointer
-    // while destructors are running.
-    JS::Rooted<JS::Value> val(aCx);
-    {
-      MOZ_ASSERT(aData < closure->mBlobImpls.Length());
-      nsRefPtr<BlobImpl> blobImpl = closure->mBlobImpls[aData];
-
-#ifdef DEBUG
-      {
-        // Blob should not be mutable.
-        bool isMutable;
-        MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
-        MOZ_ASSERT(!isMutable);
-      }
-#endif
-
-      // Let's create a new blob with the correct parent.
-      nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
-      MOZ_ASSERT(global);
-
-      nsRefPtr<Blob> newBlob = Blob::Create(global, blobImpl);
-      if (!ToJSValue(aCx, newBlob, &val)) {
-        return nullptr;
-      }
-    }
-
-    return &val.toObject();
-  }
-
-  return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr);
-}
-
-bool
-Write(JSContext* aCx, JSStructuredCloneWriter* aWriter,
-      JS::Handle<JSObject*> aObj, void* aClosure)
-{
-  MOZ_ASSERT(aClosure);
-
-  StructuredCloneClosure* closure =
-    static_cast<StructuredCloneClosure*>(aClosure);
-
-  // See if the wrapped native is a File/Blob.
-  {
-    Blob* blob = nullptr;
-    if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
-        NS_SUCCEEDED(blob->SetMutable(false)) &&
-        JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
-                           closure->mBlobImpls.Length())) {
-      closure->mBlobImpls.AppendElement(blob->Impl());
-      return true;
-    }
-  }
-
-  return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
-}
-
-const JSStructuredCloneCallbacks gCallbacks = {
-  Read,
-  Write,
-  Error,
-  nullptr,
-  nullptr,
-  nullptr
-};
-
-} // namespace
-
 namespace mozilla {
 namespace dom {
 
 bool
-ReadStructuredClone(JSContext* aCx, uint64_t* aData, size_t aDataLength,
-                    const StructuredCloneClosure& aClosure,
-                    JS::MutableHandle<JS::Value> aClone)
+StructuredCloneIPCHelper::Copy(const StructuredCloneIPCHelper& aHelper)
 {
-  void* closure = &const_cast<StructuredCloneClosure&>(aClosure);
-  return !!JS_ReadStructuredClone(aCx, aData, aDataLength,
-                                  JS_STRUCTURED_CLONE_VERSION, aClone,
-                                  &gCallbacks, closure);
+  if (!aHelper.mData) {
+    return true;
+  }
+
+  uint64_t* data = static_cast<uint64_t*>(malloc(aHelper.mDataLength));
+  if (!data) {
+    return false;
+  }
+
+  memcpy(data, aHelper.mData, aHelper.mDataLength);
+
+  mData = data;
+  mDataLength = aHelper.mDataLength;
+  mDataOwned = eAllocated;
+
+  MOZ_ASSERT(BlobImpls().IsEmpty());
+  BlobImpls().AppendElements(aHelper.BlobImpls());
+
+  MOZ_ASSERT(GetImages().IsEmpty());
+
+  return true;
 }
 
-bool
-WriteStructuredClone(JSContext* aCx, JS::Handle<JS::Value> aSource,
-                     JSAutoStructuredCloneBuffer& aBuffer,
-                     StructuredCloneClosure& aClosure)
+void
+StructuredCloneIPCHelper::Read(JSContext* aCx,
+                               JS::MutableHandle<JS::Value> aValue,
+                               ErrorResult &aRv)
 {
-  return aBuffer.write(aCx, aSource, &gCallbacks, &aClosure);
+  MOZ_ASSERT(mData);
+
+  nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
+  MOZ_ASSERT(global);
+
+  ReadFromBuffer(global, aCx, mData, mDataLength, aValue, aRv);
+}
+
+void
+StructuredCloneIPCHelper::Write(JSContext* aCx,
+                                JS::Handle<JS::Value> aValue,
+                                ErrorResult &aRv)
+{
+  MOZ_ASSERT(!mData);
+
+  StructuredCloneHelper::Write(aCx, aValue, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  mBuffer->steal(&mData, &mDataLength);
+  mBuffer = nullptr;
+  mDataOwned = eJSAllocated;
 }
 
 } // namespace dom
 } // namespace mozilla
rename from dom/ipc/StructuredCloneUtils.h
rename to dom/ipc/StructuredCloneIPCHelper.h
--- a/dom/ipc/StructuredCloneUtils.h
+++ b/dom/ipc/StructuredCloneIPCHelper.h
@@ -1,55 +1,87 @@
 /* -*- 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_StructuredCloneUtils_h
-#define mozilla_dom_StructuredCloneUtils_h
+#ifndef mozilla_dom_StructuredCloneIPCHelper_h
+#define mozilla_dom_StructuredCloneIPCHelper_h
 
-#include "nsCOMPtr.h"
-#include "nsTArray.h"
-#include "mozilla/dom/File.h"
-
-#include "js/StructuredClone.h"
+#include "mozilla/dom/StructuredCloneHelper.h"
 
 namespace mozilla {
 namespace dom {
 
-struct
-StructuredCloneClosure
+class StructuredCloneIPCHelper final : public StructuredCloneHelper
 {
-  nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
-};
+public:
+  StructuredCloneIPCHelper()
+    : StructuredCloneHelper(StructuredCloneHelper::CloningSupported,
+                            StructuredCloneHelper::TransferringNotSupported,
+                            StructuredCloneHelper::DifferentProcess)
+    , mData(nullptr)
+    , mDataLength(0)
+    , mDataOwned(eNone)
+  {}
+
+  ~StructuredCloneIPCHelper()
+  {
+    if (mDataOwned == eAllocated) {
+      free(mData);
+    } else if (mDataOwned == eJSAllocated) {
+      js_free(mData);
+    }
+  }
+
+  const nsTArray<nsRefPtr<BlobImpl>>& BlobImpls() const
+  {
+    return mBlobImplArray;
+  }
+
+  nsTArray<nsRefPtr<BlobImpl>>& BlobImpls()
+  {
+    return mBlobImplArray;
+  }
 
-struct
-StructuredCloneData
-{
-  StructuredCloneData() : mData(nullptr), mDataLength(0) {}
+  bool Copy(const StructuredCloneIPCHelper& aHelper);
+
+  void Read(JSContext* aCx,
+            JS::MutableHandle<JS::Value> aValue,
+            ErrorResult &aRv);
+
+  void Write(JSContext* aCx,
+             JS::Handle<JS::Value> aValue,
+             ErrorResult &aRv);
+
+  void UseExternalData(uint64_t* aData, size_t aDataLength)
+  {
+    MOZ_ASSERT(!mData);
+    mData = aData;
+    mDataLength = aDataLength;
+    MOZ_ASSERT(mDataOwned == eNone);
+  }
+
+  uint64_t* Data() const
+  {
+    return mData;
+  }
+
+  size_t DataLength() const
+  {
+    return mDataLength;
+  }
+
+private:
   uint64_t* mData;
   size_t mDataLength;
-  StructuredCloneClosure mClosure;
+  enum {
+    eNone,
+    eAllocated,
+    eJSAllocated
+  } mDataOwned;
 };
 
-bool
-ReadStructuredClone(JSContext* aCx, uint64_t* aData, size_t aDataLength,
-                    const StructuredCloneClosure& aClosure,
-                    JS::MutableHandle<JS::Value> aClone);
-
-inline bool
-ReadStructuredClone(JSContext* aCx, const StructuredCloneData& aData,
-                    JS::MutableHandle<JS::Value> aClone)
-{
-  return ReadStructuredClone(aCx, aData.mData, aData.mDataLength,
-                             aData.mClosure, aClone);
-}
-
-bool
-WriteStructuredClone(JSContext* aCx, JS::Handle<JS::Value> aSource,
-                     JSAutoStructuredCloneBuffer& aBuffer,
-                     StructuredCloneClosure& aClosure);
-
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_StructuredCloneUtils_h
+#endif // mozilla_dom_StructuredCloneIPCHelper_h
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -78,17 +78,17 @@
 #include "nsPIWindowRoot.h"
 #include "nsLayoutUtils.h"
 #include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
 #include "nsWeakReference.h"
 #include "nsWindowWatcher.h"
 #include "PermissionMessageUtils.h"
 #include "PuppetWidget.h"
-#include "StructuredCloneUtils.h"
+#include "StructuredCloneIPCHelper.h"
 #include "nsViewportInfo.h"
 #include "nsILoadContext.h"
 #include "ipc/nsGUIEventIPC.h"
 #include "mozilla/gfx/Matrix.h"
 #include "UnitTransforms.h"
 #include "ClientLayerManager.h"
 #include "LayersLogging.h"
 #include "nsIOService.h"
@@ -232,34 +232,35 @@ TabChildBase::GetPresShell() const
 }
 
 void
 TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName,
                                             const nsAString& aJSONData)
 {
     AutoSafeJSContext cx;
     JS::Rooted<JS::Value> json(cx, JS::NullValue());
-    StructuredCloneData cloneData;
-    JSAutoStructuredCloneBuffer buffer;
+    StructuredCloneIPCHelper helper;
     if (JS_ParseJSON(cx,
                       static_cast<const char16_t*>(aJSONData.BeginReading()),
                       aJSONData.Length(),
                       &json)) {
-        WriteStructuredClone(cx, json, buffer, cloneData.mClosure);
-        cloneData.mData = buffer.data();
-        cloneData.mDataLength = buffer.nbytes();
+        ErrorResult rv;
+        helper.Write(cx, json, rv);
+        if (NS_WARN_IF(rv.Failed())) {
+            return;
+        }
     }
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
     // Let the BrowserElementScrolling helper (if it exists) for this
     // content manipulate the frame state.
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
     mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal), nullptr,
-                       aMessageName, false, &cloneData, nullptr, nullptr, nullptr);
+                       aMessageName, false, &helper, nullptr, nullptr, nullptr);
 }
 
 bool
 TabChildBase::UpdateFrameHandler(const FrameMetrics& aFrameMetrics)
 {
   MOZ_ASSERT(aFrameMetrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID);
 
   if (aFrameMetrics.IsRootContent()) {
@@ -2447,22 +2448,23 @@ TabChild::RecvLoadRemoteScript(const nsS
 bool
 TabChild::RecvAsyncMessage(const nsString& aMessage,
                            const ClonedMessageData& aData,
                            InfallibleTArray<CpowEntry>&& aCpows,
                            const IPC::Principal& aPrincipal)
 {
   if (mTabChildGlobal) {
     nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
-    StructuredCloneData cloneData = UnpackClonedMessageDataForChild(aData);
+    StructuredCloneIPCHelper helper;
+    UnpackClonedMessageDataForChild(aData, helper);
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
     CrossProcessCpowHolder cpows(Manager(), aCpows);
     mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal), nullptr,
-                       aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
+                       aMessage, false, &helper, &cpows, aPrincipal, nullptr);
   }
   return true;
 }
 
 bool
 TabChild::RecvAppOfflineStatus(const uint32_t& aId, const bool& aOffline)
 {
   // Instantiate the service to make sure gIOService is initialized
@@ -2882,24 +2884,24 @@ TabChild::SetTabId(const TabId& aTabId)
 
   mUniqueId = aTabId;
   NestedTabChildMap()[mUniqueId] = this;
 }
 
 bool
 TabChild::DoSendBlockingMessage(JSContext* aCx,
                                 const nsAString& aMessage,
-                                const StructuredCloneData& aData,
+                                StructuredCloneIPCHelper& aHelper,
                                 JS::Handle<JSObject *> aCpows,
                                 nsIPrincipal* aPrincipal,
                                 nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal,
                                 bool aIsSync)
 {
   ClonedMessageData data;
-  if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
+  if (!BuildClonedMessageDataForChild(Manager(), aHelper, data)) {
     return false;
   }
   InfallibleTArray<CpowEntry> cpows;
   if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
     return false;
   }
   if (aIsSync) {
     return SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
@@ -2908,22 +2910,22 @@ TabChild::DoSendBlockingMessage(JSContex
 
   return SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
                         Principal(aPrincipal), aRetVal);
 }
 
 bool
 TabChild::DoSendAsyncMessage(JSContext* aCx,
                              const nsAString& aMessage,
-                             const StructuredCloneData& aData,
+                             StructuredCloneIPCHelper& aHelper,
                              JS::Handle<JSObject *> aCpows,
                              nsIPrincipal* aPrincipal)
 {
   ClonedMessageData data;
-  if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
+  if (!BuildClonedMessageDataForChild(Manager(), aHelper, data)) {
     return false;
   }
   InfallibleTArray<CpowEntry> cpows;
   if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
     return false;
   }
   return SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
                           Principal(aPrincipal));
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -272,24 +272,24 @@ public:
     NS_DECL_NSIOBSERVER
     NS_DECL_NSITOOLTIPLISTENER
 
     /**
      * MessageManagerCallback methods that we override.
      */
     virtual bool DoSendBlockingMessage(JSContext* aCx,
                                        const nsAString& aMessage,
-                                       const mozilla::dom::StructuredCloneData& aData,
+                                       mozilla::dom::StructuredCloneIPCHelper& aHelper,
                                        JS::Handle<JSObject *> aCpows,
                                        nsIPrincipal* aPrincipal,
                                        nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal,
                                        bool aIsSync) override;
     virtual bool DoSendAsyncMessage(JSContext* aCx,
                                     const nsAString& aMessage,
-                                    const mozilla::dom::StructuredCloneData& aData,
+                                    mozilla::dom::StructuredCloneIPCHelper& aHelper,
                                     JS::Handle<JSObject *> aCpows,
                                     nsIPrincipal* aPrincipal) override;
     virtual bool DoUpdateZoomConstraints(const uint32_t& aPresShellId,
                                          const ViewID& aViewId,
                                          const Maybe<ZoomConstraints>& aConstraints) override;
     virtual bool RecvLoadURL(const nsCString& aURI,
                              const BrowserConfiguration& aConfiguration) override;
     virtual bool RecvCacheFileDescriptor(const nsString& aPath,
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -74,17 +74,17 @@
 #include "nsPIWindowWatcher.h"
 #include "nsPresShell.h"
 #include "nsPrintfCString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsWindowWatcher.h"
 #include "private/pprio.h"
 #include "PermissionMessageUtils.h"
-#include "StructuredCloneUtils.h"
+#include "StructuredCloneIPCHelper.h"
 #include "ColorPickerParent.h"
 #include "FilePickerParent.h"
 #include "TabChild.h"
 #include "LoadContext.h"
 #include "nsNetCID.h"
 #include "nsIAuthInformation.h"
 #include "nsIAuthPromptCallback.h"
 #include "SourceSurfaceRawData.h"
@@ -1842,19 +1842,21 @@ TabParent::RecvSyncMessage(const nsStrin
   if (Manager()->IsContentParent()) {
     ContentParent* parent = Manager()->AsContentParent();
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
-  StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
+  StructuredCloneIPCHelper helper;
+  ipc::UnpackClonedMessageDataForParent(aData, helper);
+
   CrossProcessCpowHolder cpows(Manager(), aCpows);
-  return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aRetVal);
+  return ReceiveMessage(aMessage, true, &helper, &cpows, aPrincipal, aRetVal);
 }
 
 bool
 TabParent::RecvRpcMessage(const nsString& aMessage,
                           const ClonedMessageData& aData,
                           InfallibleTArray<CpowEntry>&& aCpows,
                           const IPC::Principal& aPrincipal,
                           nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal)
@@ -1864,19 +1866,21 @@ TabParent::RecvRpcMessage(const nsString
   if (Manager()->IsContentParent()) {
     ContentParent* parent = Manager()->AsContentParent();
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
-  StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
+  StructuredCloneIPCHelper helper;
+  ipc::UnpackClonedMessageDataForParent(aData, helper);
+
   CrossProcessCpowHolder cpows(Manager(), aCpows);
-  return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aRetVal);
+  return ReceiveMessage(aMessage, true, &helper, &cpows, aPrincipal, aRetVal);
 }
 
 bool
 TabParent::RecvAsyncMessage(const nsString& aMessage,
                             const ClonedMessageData& aData,
                             InfallibleTArray<CpowEntry>&& aCpows,
                             const IPC::Principal& aPrincipal)
 {
@@ -1885,19 +1889,21 @@ TabParent::RecvAsyncMessage(const nsStri
   if (Manager()->IsContentParent()) {
     ContentParent* parent = Manager()->AsContentParent();
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
-  StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
+  StructuredCloneIPCHelper helper;
+  ipc::UnpackClonedMessageDataForParent(aData, helper);
+
   CrossProcessCpowHolder cpows(Manager(), aCpows);
-  return ReceiveMessage(aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
+  return ReceiveMessage(aMessage, false, &helper, &cpows, aPrincipal, nullptr);
 }
 
 bool
 TabParent::RecvSetCursor(const uint32_t& aCursor, const bool& aForce)
 {
   mCursor = static_cast<nsCursor>(aCursor);
   mCustomCursor = nullptr;
 
@@ -2621,31 +2627,31 @@ TabParent::RecvDispatchFocusToTopLevelWi
     widget->SetFocus(false);
   }
   return true;
 }
 
 bool
 TabParent::ReceiveMessage(const nsString& aMessage,
                           bool aSync,
-                          const StructuredCloneData* aCloneData,
+                          StructuredCloneIPCHelper* aHelper,
                           CpowHolder* aCpows,
                           nsIPrincipal* aPrincipal,
                           nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal)
 {
   nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
   if (frameLoader && frameLoader->GetFrameMessageManager()) {
     nsRefPtr<nsFrameMessageManager> manager =
       frameLoader->GetFrameMessageManager();
 
     manager->ReceiveMessage(mFrameElement,
                             frameLoader,
                             aMessage,
                             aSync,
-                            aCloneData,
+                            aHelper,
                             aCpows,
                             aPrincipal,
                             aRetVal);
   }
   return true;
 }
 
 // nsIAuthPromptProvider
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -62,17 +62,17 @@ class DataSourceSurface;
 } // namespace gfx
 
 namespace dom {
 
 class ClonedMessageData;
 class nsIContentParent;
 class Element;
 class DataTransfer;
-struct StructuredCloneData;
+class StructuredCloneIPCHelper;
 
 class TabParent final : public PBrowserParent
                       , public nsIDOMEventListener
                       , public nsITabParent
                       , public nsIAuthPromptProvider
                       , public nsISecureBrowserUI
                       , public nsSupportsWeakReference
                       , public TabContext
@@ -438,17 +438,17 @@ public:
     layout::RenderFrameParent* GetRenderFrame();
 
     virtual PWebBrowserPersistDocumentParent* AllocPWebBrowserPersistDocumentParent(const uint64_t& aOuterWindowID) override;
     virtual bool DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumentParent* aActor) override;
 
 protected:
     bool ReceiveMessage(const nsString& aMessage,
                         bool aSync,
-                        const StructuredCloneData* aCloneData,
+                        StructuredCloneIPCHelper* aHelper,
                         mozilla::jsipc::CpowHolder* aCpows,
                         nsIPrincipal* aPrincipal,
                         nsTArray<OwningSerializedStructuredCloneBuffer>* aJSONRetVal = nullptr);
 
     virtual bool RecvAsyncAuthPrompt(const nsCString& aUri,
                                      const nsString& aRealm,
                                      const uint64_t& aCallbackId) override;
 
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -32,17 +32,17 @@ EXPORTS.mozilla.dom += [
     'CrashReporterChild.h',
     'CrashReporterParent.h',
     'FilePickerParent.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
     'NuwaChild.h',
     'NuwaParent.h',
     'PermissionMessageUtils.h',
-    'StructuredCloneUtils.h',
+    'StructuredCloneIPCHelper.h',
     'TabChild.h',
     'TabContext.h',
     'TabMessageUtils.h',
     'TabParent.h',
 ]
 
 EXPORTS.mozilla += [
     'AppProcessChecker.h',
@@ -65,17 +65,17 @@ UNIFIED_SOURCES += [
     'nsIContentChild.cpp',
     'nsIContentParent.cpp',
     'NuwaChild.cpp',
     'NuwaParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
     'ScreenManagerParent.cpp',
-    'StructuredCloneUtils.cpp',
+    'StructuredCloneIPCHelper.cpp',
     'TabChild.cpp',
     'TabContext.cpp',
     'TabMessageUtils.cpp',
     'TabParent.cpp',
 ]
 
 # Blob.cpp cannot be compiled in unified mode because it triggers a fatal gcc warning.
 # CrashReporterChild.cpp cannot be compiled in unified mode because of name clashes
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIContentChild.h"
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/DOMTypes.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
-#include "mozilla/dom/StructuredCloneUtils.h"
+#include "mozilla/dom/StructuredCloneIPCHelper.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 
 #include "nsPrintfCString.h"
 #include "xpcpublic.h"
 
 using namespace mozilla::ipc;
@@ -112,18 +112,20 @@ nsIContentChild::GetOrCreateActorForBlob
 bool
 nsIContentChild::RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
                                   InfallibleTArray<CpowEntry>&& aCpows,
                                   const IPC::Principal& aPrincipal)
 {
   nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::GetChildProcessManager();
   if (cpm) {
-    StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
+    StructuredCloneIPCHelper helper;
+    ipc::UnpackClonedMessageDataForChild(aData, helper);
+
     CrossProcessCpowHolder cpows(this, aCpows);
     cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()), nullptr,
-                        aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
+                        aMsg, false, &helper, &cpows, aPrincipal, nullptr);
   }
   return true;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -8,17 +8,17 @@
 
 #include "mozilla/AppProcessChecker.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/PTabContext.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
-#include "mozilla/dom/StructuredCloneUtils.h"
+#include "mozilla/dom/StructuredCloneIPCHelper.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/unused.h"
 
 #include "nsFrameMessageManager.h"
 #include "nsPrintfCString.h"
 #include "xpcpublic.h"
@@ -196,20 +196,22 @@ nsIContentParent::RecvSyncMessage(const 
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
-    StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
+    StructuredCloneIPCHelper helper;
+    ipc::UnpackClonedMessageDataForParent(aData, helper);
+
     CrossProcessCpowHolder cpows(this, aCpows);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr,
-                        aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
+                        aMsg, true, &helper, &cpows, aPrincipal, aRetvals);
   }
   return true;
 }
 
 bool
 nsIContentParent::RecvRpcMessage(const nsString& aMsg,
                                  const ClonedMessageData& aData,
                                  InfallibleTArray<CpowEntry>&& aCpows,
@@ -223,20 +225,22 @@ nsIContentParent::RecvRpcMessage(const n
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
-    StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
+    StructuredCloneIPCHelper helper;
+    ipc::UnpackClonedMessageDataForParent(aData, helper);
+
     CrossProcessCpowHolder cpows(this, aCpows);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr,
-                        aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
+                        aMsg, true, &helper, &cpows, aPrincipal, aRetvals);
   }
   return true;
 }
 
 bool
 nsIContentParent::RecvAsyncMessage(const nsString& aMsg,
                                    const ClonedMessageData& aData,
                                    InfallibleTArray<CpowEntry>&& aCpows,
@@ -249,18 +253,20 @@ nsIContentParent::RecvAsyncMessage(const
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
-    StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
+    StructuredCloneIPCHelper helper;
+    ipc::UnpackClonedMessageDataForParent(aData, helper);
+
     CrossProcessCpowHolder cpows(this, aCpows);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr,
-                        aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
+                        aMsg, false, &helper, &cpows, aPrincipal, nullptr);
   }
   return true;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/messagechannel/SharedMessagePortMessage.cpp
+++ b/dom/messagechannel/SharedMessagePortMessage.cpp
@@ -41,17 +41,17 @@ SharedMessagePortMessage::Read(nsISuppor
 }
 
 void
 SharedMessagePortMessage::Write(JSContext* aCx,
                                 JS::Handle<JS::Value> aValue,
                                 JS::Handle<JS::Value> aTransfer,
                                 ErrorResult& aRv)
 {
-  StructuredCloneHelper::Write(aCx, aValue, aTransfer, true, aRv);
+  StructuredCloneHelper::Write(aCx, aValue, aTransfer, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   FallibleTArray<uint8_t> cloneData;
 
   MoveBufferDataToArray(cloneData, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
--- a/dom/messagechannel/SharedMessagePortMessage.h
+++ b/dom/messagechannel/SharedMessagePortMessage.h
@@ -18,17 +18,18 @@ class MessagePortParent;
 class SharedMessagePortMessage final : public StructuredCloneHelper
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(SharedMessagePortMessage)
 
   nsTArray<uint8_t> mData;
 
   SharedMessagePortMessage()
-    : StructuredCloneHelper(CloningSupported, TransferringSupported)
+    : StructuredCloneHelper(CloningSupported, TransferringSupported,
+                            DifferentProcess)
   {}
 
   void Read(nsISupports* aParent,
             JSContext* aCx,
             JS::MutableHandle<JS::Value> aValue,
             ErrorResult& aRv);
 
   void Write(JSContext* aCx,
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/MediaStreamError.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 #include "jsfriendapi.h"
+#include "js/StructuredClone.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsJSEnvironment.h"
 #include "nsJSPrincipals.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
 #include "PromiseCallback.h"
--- a/dom/push/PushManager.cpp
+++ b/dom/push/PushManager.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
 
 #include "nsIGlobalObject.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIPushClient.h"
 
+#include "nsComponentManagerUtils.h"
 #include "nsFrameMessageManager.h"
 #include "nsContentCID.h"
 
 #include "WorkerRunnable.h"
 #include "WorkerPrivate.h"
 #include "WorkerScope.h"
 
 namespace mozilla {
--- a/dom/workers/DataStore.cpp
+++ b/dom/workers/DataStore.cpp
@@ -219,26 +219,27 @@ public:
                        const nsMainThreadPtrHandle<DataStore>& aBackingStore,
                        Promise* aWorkerPromise,
                        JSContext* aCx,
                        JS::Handle<JS::Value> aObj,
                        const StringOrUnsignedLong& aId,
                        const nsAString& aRevisionId,
                        ErrorResult& aRv)
     : DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
-    , StructuredCloneHelper(CloningNotSupported, TransferringNotSupported)
+    , StructuredCloneHelper(CloningNotSupported, TransferringNotSupported,
+                            SameProcessDifferentThread)
     , mId(aId)
     , mRevisionId(aRevisionId)
     , mRv(aRv)
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
 
     // This needs to be structured cloned while it's still on the worker thread.
-    Write(aCx, aObj, true, mRv);
+    Write(aCx, aObj, mRv);
     NS_WARN_IF(mRv.Failed());
   }
 
 protected:
   virtual bool
   MainThreadRun() override
   {
     AssertIsOnMainThread();
@@ -280,26 +281,27 @@ public:
                        const nsMainThreadPtrHandle<DataStore>& aBackingStore,
                        Promise* aWorkerPromise,
                        JSContext* aCx,
                        JS::Handle<JS::Value> aObj,
                        const Optional<StringOrUnsignedLong>& aId,
                        const nsAString& aRevisionId,
                        ErrorResult& aRv)
     : DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
-    , StructuredCloneHelper(CloningNotSupported, TransferringNotSupported)
+    , StructuredCloneHelper(CloningNotSupported, TransferringNotSupported,
+                            SameProcessDifferentThread)
     , mId(aId)
     , mRevisionId(aRevisionId)
     , mRv(aRv)
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
 
     // This needs to be structured cloned while it's still on the worker thread.
-    Write(aCx, aObj, true, mRv);
+    Write(aCx, aObj, mRv);
     NS_WARN_IF(mRv.Failed());
   }
 
 protected:
   virtual bool
   MainThreadRun() override
   {
     AssertIsOnMainThread();
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -75,17 +75,18 @@ namespace {
 class ServiceWorkerClientPostMessageRunnable final
   : public nsRunnable
   , public StructuredCloneHelper
 {
   uint64_t mWindowId;
 
 public:
   explicit ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId)
-    : StructuredCloneHelper(CloningSupported, TransferringSupported)
+    : StructuredCloneHelper(CloningSupported, TransferringSupported,
+                            SameProcessDifferentThread)
     , mWindowId(aWindowId)
   {}
 
   NS_IMETHOD
   Run()
   {
     AssertIsOnMainThread();
     nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
@@ -184,17 +185,17 @@ ServiceWorkerClient::PostMessage(JSConte
     }
 
     transferable.setObject(*array);
   }
 
   nsRefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
     new ServiceWorkerClientPostMessageRunnable(mWindowId);
 
-  runnable->Write(aCx, aMessage, transferable, true, aRv);
+  runnable->Write(aCx, aMessage, transferable, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   aRv = NS_DispatchToMainThread(runnable);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -30,16 +30,17 @@
 #include "mozilla/ErrorNames.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/Headers.h"
+#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/indexedDB/IDBFactory.h"
 #include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/NotificationEvent.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/ipc/BackgroundChild.h"
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -600,17 +600,18 @@ class MessageEventRunnable final : publi
   // 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)
   : WorkerRunnable(aWorkerPrivate, aBehavior)
-  , StructuredCloneHelper(CloningSupported, TransferringSupported)
+  , StructuredCloneHelper(CloningSupported, TransferringSupported,
+                          SameProcessDifferentThread)
   , mMessagePortSerial(aMessagePortSerial)
   , mToMessagePort(aToMessagePort)
   {
   }
 
   void
   SetMessageSource(ServiceWorkerClientInfo* aSource)
   {
@@ -2794,17 +2795,17 @@ WorkerPrivateParent<Derived>::PostMessag
     transferable.setObject(*array);
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(ParentAsWorkerPrivate(),
                              WorkerRunnable::WorkerThreadModifyBusyCount,
                              aToMessagePort, aMessagePortSerial);
 
-  runnable->Write(aCx, aMessage, transferable, true, aRv);
+  runnable->Write(aCx, aMessage, transferable, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   runnable->SetMessageSource(aClientInfo);
 
   if (!runnable->Dispatch(aCx)) {
     aRv.Throw(NS_ERROR_FAILURE);
@@ -5551,17 +5552,17 @@ WorkerPrivate::PostMessageToParentIntern
     transferable.setObject(*array);
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(this,
                              WorkerRunnable::ParentThreadUnchangedBusyCount,
                              aToMessagePort, aMessagePortSerial);
 
-  runnable->Write(aCx, aMessage, transferable, true, aRv);
+  runnable->Write(aCx, aMessage, transferable, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   if (!runnable->Dispatch(aCx)) {
     aRv = NS_ERROR_FAILURE;
   }
 }
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -256,17 +256,18 @@ class SendRunnable final
   nsString mStringBody;
   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
   bool mHasUploadListeners;
 
 public:
   SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
                const nsAString& aStringBody)
   : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
-  , StructuredCloneHelper(CloningSupported, TransferringNotSupported)
+  , StructuredCloneHelper(CloningSupported, TransferringNotSupported,
+                          SameProcessDifferentThread)
   , mStringBody(aStringBody)
   , mHasUploadListeners(false)
   {
   }
 
   void SetHaveUploadListeners(bool aHasUploadListeners)
   {
     mHasUploadListeners = aHasUploadListeners;
@@ -561,27 +562,29 @@ public:
       JS_CallValueTracer(aTrc, &mStateData->mResponse,
                          "XMLHttpRequest::StateData::mResponse");
     }
   };
 
   EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType,
                 bool aLengthComputable, uint64_t aLoaded, uint64_t aTotal)
   : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
-    StructuredCloneHelper(CloningSupported, TransferringNotSupported),
+    StructuredCloneHelper(CloningSupported, TransferringNotSupported,
+                          SameProcessDifferentThread),
     mType(aType), mResponse(JS::UndefinedValue()), mLoaded(aLoaded),
     mTotal(aTotal), mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0),
     mReadyState(0), mUploadEvent(aUploadEvent), mProgressEvent(true),
     mLengthComputable(aLengthComputable), mUseCachedArrayBufferResponse(false),
     mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK)
   { }
 
   EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType)
   : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
-    StructuredCloneHelper(CloningSupported, TransferringNotSupported),
+    StructuredCloneHelper(CloningSupported, TransferringNotSupported,
+                          SameProcessDifferentThread),
     mType(aType), mResponse(JS::UndefinedValue()), mLoaded(0), mTotal(0),
     mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
     mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0),
     mUseCachedArrayBufferResponse(false), mResponseTextResult(NS_OK),
     mStatusResult(NS_OK), mResponseResult(NS_OK)
   { }
 
 private:
@@ -1227,17 +1230,17 @@ EventRunnable::PreDispatch(JSContext* aC
               mResponseResult = NS_ERROR_OUT_OF_MEMORY;
               doClone = false;
             }
           }
         }
 
         if (doClone) {
           ErrorResult rv;
-          Write(aCx, response, transferable, false, rv);
+          Write(aCx, response, transferable, rv);
           if (NS_WARN_IF(rv.Failed())) {
             NS_WARNING("Failed to clone response!");
             mResponseResult = rv.StealNSResult();
             mProxy->mArrayBufferResponseWasTransferred = false;
           }
         }
       }
     }
@@ -2147,17 +2150,17 @@ XMLHttpRequest::Send(JS::Handle<JSObject
       return;
     }
     valToClone.setString(bodyStr);
   }
 
   nsRefPtr<SendRunnable> sendRunnable =
     new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
 
-  sendRunnable->Write(cx, valToClone, false, aRv);
+  sendRunnable->Write(cx, valToClone, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   SendInternal(sendRunnable, aRv);
 }
 
 void
@@ -2188,17 +2191,17 @@ XMLHttpRequest::Send(Blob& aBody, ErrorR
   aRv = blobImpl->SetMutable(false);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   nsRefPtr<SendRunnable> sendRunnable =
     new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
 
-  sendRunnable->Write(cx, value, false, aRv);
+  sendRunnable->Write(cx, value, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   SendInternal(sendRunnable, aRv);
 }
 
 void
@@ -2221,17 +2224,17 @@ XMLHttpRequest::Send(nsFormData& aBody, 
   if (!GetOrCreateDOMReflector(cx, &aBody, &value)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   nsRefPtr<SendRunnable> sendRunnable =
     new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
 
-  sendRunnable->Write(cx, value, false, aRv);
+  sendRunnable->Write(cx, value, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   SendInternal(sendRunnable, aRv);
 }
 
 void
--- a/widget/gonk/nsClipboard.cpp
+++ b/widget/gonk/nsClipboard.cpp
@@ -9,16 +9,17 @@
 #include "ImageOps.h"
 #include "imgIContainer.h"
 #include "imgTools.h"
 #include "mozilla/dom/ContentChild.h"
 #include "nsClipboardProxy.h"
 #include "nsISupportsPrimitives.h"
 #include "nsComponentManagerUtils.h"
 #include "nsCOMPtr.h"
+#include "nsServiceManagerUtils.h"
 #include "nsStringStream.h"
 #include "nsXULAppAPI.h"
 
 using namespace mozilla;
 using mozilla::dom::ContentChild;
 
 #define LOG_TAG "Clipboard"
 #define LOGI(args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, ## args)