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 293204 ed6830f48c58fcd145c1967f3f879cc67553377d
parent 293203 50fd13696678be08cc9fdd953905fffc72b6aa48
child 293205 c9e469c6b9159e42c83dacdc91b5084b9600a93e
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1198795
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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)