Backed out changeset f6d29009ae0a (bug 1184557) for crashes in fetch-csp.https.html web platform tests CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 22 Jul 2015 13:57:09 -0700
changeset 285877 9be3d57c2e15cc11be2cb0c427ef231adfa9ce59
parent 285876 01f9844491ce68a93776dab3cafd74789942b2f9
child 285878 1178c11561bced95d152701ce3865b16c4d6d1ed
push idunknown
push userunknown
push dateunknown
bugs1184557
milestone42.0a1
backs outf6d29009ae0a599059d750ced11a8654a39fe224
Backed out changeset f6d29009ae0a (bug 1184557) for crashes in fetch-csp.https.html web platform tests CLOSED TREE
dom/base/PostMessageEvent.cpp
dom/base/PostMessageEvent.h
dom/base/StructuredCloneHelper.cpp
dom/base/StructuredCloneHelper.h
dom/base/nsGlobalWindow.cpp
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -18,16 +18,256 @@
 #include "nsGlobalWindow.h"
 #include "nsIPresShell.h"
 #include "nsIPrincipal.h"
 #include "nsPresContext.h"
 
 namespace mozilla {
 namespace dom {
 
+namespace {
+
+struct StructuredCloneInfo
+{
+  PostMessageEvent* event;
+  nsPIDOMWindow* window;
+
+  // This hashtable contains the transferred ports - used to avoid duplicates.
+  nsTArray<nsRefPtr<MessagePortBase>> transferredPorts;
+
+  // This array is populated when the ports are cloned.
+  nsTArray<nsRefPtr<MessagePortBase>> clonedPorts;
+};
+
+} // namespace
+
+const JSStructuredCloneCallbacks PostMessageEvent::sPostMessageCallbacks = {
+  PostMessageEvent::ReadStructuredClone,
+  PostMessageEvent::WriteStructuredClone,
+  nullptr,
+  PostMessageEvent::ReadTransferStructuredClone,
+  PostMessageEvent::TransferStructuredClone,
+  PostMessageEvent::FreeTransferStructuredClone
+};
+
+/* static */ JSObject*
+PostMessageEvent::ReadStructuredClone(JSContext* cx,
+                                      JSStructuredCloneReader* reader,
+                                      uint32_t tag,
+                                      uint32_t data,
+                                      void* closure)
+{
+  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
+  NS_ASSERTION(scInfo, "Must have scInfo!");
+
+  if (tag == SCTAG_DOM_BLOB) {
+    NS_ASSERTION(!data, "Data should be empty");
+
+    // What we get back from the reader is a BlobImpl.
+    // From that we create a new File.
+    BlobImpl* blobImpl;
+    if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) {
+      MOZ_ASSERT(blobImpl);
+
+      // 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(cx);
+      {
+        nsRefPtr<Blob> blob = Blob::Create(scInfo->window, blobImpl);
+        if (!ToJSValue(cx, blob, &val)) {
+          return nullptr;
+        }
+      }
+
+      return &val.toObject();
+    }
+  }
+
+  if (tag == SCTAG_DOM_FILELIST) {
+    NS_ASSERTION(!data, "Data should be empty");
+
+    // What we get back from the reader is a FileListClonedData.
+    // From that we create a new FileList.
+    FileListClonedData* fileListClonedData;
+    if (JS_ReadBytes(reader, &fileListClonedData, sizeof(fileListClonedData))) {
+      MOZ_ASSERT(fileListClonedData);
+
+      // nsRefPtr<FileList> 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(cx);
+      {
+        nsRefPtr<FileList> fileList =
+          FileList::Create(scInfo->window, fileListClonedData);
+        if (!fileList || !ToJSValue(cx, fileList, &val)) {
+          return nullptr;
+        }
+      }
+
+      return &val.toObject();
+    }
+  }
+
+  const JSStructuredCloneCallbacks* runtimeCallbacks =
+    js::GetContextStructuredCloneCallbacks(cx);
+
+  if (runtimeCallbacks) {
+    return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
+  }
+
+  return nullptr;
+}
+
+/* static */ bool
+PostMessageEvent::WriteStructuredClone(JSContext* cx,
+                                       JSStructuredCloneWriter* writer,
+                                       JS::Handle<JSObject*> obj,
+                                       void *closure)
+{
+  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
+  NS_ASSERTION(scInfo, "Must have scInfo!");
+
+  // See if this is a File/Blob object.
+  {
+    Blob* blob = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
+      BlobImpl* blobImpl = blob->Impl();
+      if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
+          JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
+        scInfo->event->StoreISupports(blobImpl);
+        return true;
+      }
+    }
+  }
+
+  // See if this is a FileList object.
+  {
+    FileList* fileList = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, obj, fileList))) {
+      nsRefPtr<FileListClonedData> fileListClonedData =
+        fileList->CreateClonedData();
+      MOZ_ASSERT(fileListClonedData);
+      FileListClonedData* ptr = fileListClonedData.get();
+      if (JS_WriteUint32Pair(writer, SCTAG_DOM_FILELIST, 0) &&
+          JS_WriteBytes(writer, &ptr, sizeof(ptr))) {
+        scInfo->event->StoreISupports(fileListClonedData);
+        return true;
+      }
+    }
+  }
+
+  const JSStructuredCloneCallbacks* runtimeCallbacks =
+    js::GetContextStructuredCloneCallbacks(cx);
+
+  if (runtimeCallbacks) {
+    return runtimeCallbacks->write(cx, writer, obj, nullptr);
+  }
+
+  return false;
+}
+
+/* static */ bool
+PostMessageEvent::ReadTransferStructuredClone(JSContext* aCx,
+                                              JSStructuredCloneReader* reader,
+                                              uint32_t tag, void* aData,
+                                              uint64_t aExtraData,
+                                              void* aClosure,
+                                              JS::MutableHandle<JSObject*> returnObject)
+{
+  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
+  NS_ASSERTION(scInfo, "Must have scInfo!");
+
+  if (tag == SCTAG_DOM_MAP_MESSAGEPORT) {
+    MOZ_ASSERT(!aData);
+    // aExtraData is the index of this port identifier.
+    ErrorResult rv;
+    nsRefPtr<MessagePort> port =
+      MessagePort::Create(scInfo->window,
+                          scInfo->event->GetPortIdentifier(aExtraData),
+                          rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      return false;
+    }
+
+    scInfo->clonedPorts.AppendElement(port);
+
+    JS::Rooted<JS::Value> value(aCx);
+    if (!GetOrCreateDOMReflector(aCx, port, &value)) {
+      JS_ClearPendingException(aCx);
+      return false;
+    }
+
+    returnObject.set(&value.toObject());
+    return true;
+  }
+
+  return false;
+}
+
+/* static */ bool
+PostMessageEvent::TransferStructuredClone(JSContext* aCx,
+                                          JS::Handle<JSObject*> aObj,
+                                          void* aClosure,
+                                          uint32_t* aTag,
+                                          JS::TransferableOwnership* aOwnership,
+                                          void** aContent,
+                                          uint64_t* aExtraData)
+{
+  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
+  NS_ASSERTION(scInfo, "Must have scInfo!");
+
+  MessagePortBase* port = nullptr;
+  nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
+  if (NS_SUCCEEDED(rv)) {
+    if (scInfo->transferredPorts.Contains(port)) {
+      // No duplicates.
+      return false;
+    }
+
+    // We use aExtraData to store the index of this new port identifier.
+    MessagePortIdentifier* identifier =
+      scInfo->event->NewPortIdentifier(aExtraData);
+
+    if (!port->CloneAndDisentangle(*identifier)) {
+      return false;
+    }
+
+    scInfo->transferredPorts.AppendElement(port);
+
+    *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
+    *aOwnership = JS::SCTAG_TMO_CUSTOM;
+    *aContent = nullptr;
+
+    return true;
+  }
+
+  return false;
+}
+
+/* static */ void
+PostMessageEvent::FreeTransferStructuredClone(uint32_t aTag,
+                                              JS::TransferableOwnership aOwnership,
+                                              void *aContent,
+                                              uint64_t aExtraData,
+                                              void* aClosure)
+{
+  if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
+    MOZ_ASSERT(aClosure);
+    MOZ_ASSERT(!aContent);
+
+    StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
+    MessagePort::ForceClose(scInfo->event->GetPortIdentifier(aExtraData));
+  }
+}
+
 PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
                                    const nsAString& aCallerOrigin,
                                    nsGlobalWindow* aTargetWindow,
                                    nsIPrincipal* aProvidedPrincipal,
                                    bool aTrustedCaller)
 : mSource(aSource),
   mCallerOrigin(aCallerOrigin),
   mTargetWindow(aTargetWindow),
@@ -37,16 +277,30 @@ PostMessageEvent::PostMessageEvent(nsGlo
   MOZ_COUNT_CTOR(PostMessageEvent);
 }
 
 PostMessageEvent::~PostMessageEvent()
 {
   MOZ_COUNT_DTOR(PostMessageEvent);
 }
 
+const MessagePortIdentifier&
+PostMessageEvent::GetPortIdentifier(uint64_t aId)
+{
+  MOZ_ASSERT(aId < mPortIdentifiers.Length());
+  return mPortIdentifiers[aId];
+}
+
+MessagePortIdentifier*
+PostMessageEvent::NewPortIdentifier(uint64_t* aPosition)
+{
+  *aPosition = mPortIdentifiers.Length();
+  return mPortIdentifiers.AppendElement();
+}
+
 NS_IMETHODIMP
 PostMessageEvent::Run()
 {
   MOZ_ASSERT(mTargetWindow->IsOuterWindow(),
              "should have been passed an outer window!");
   MOZ_ASSERT(!mSource || mSource->IsOuterWindow(),
              "should have been passed an outer window!");
 
@@ -88,34 +342,38 @@ PostMessageEvent::Run()
     //       don't do that in other places it seems better to hold the line for
     //       now.  Long-term, we want HTML5 to address this so that we can
     //       be compliant while being safer.
     if (!targetPrin->Equals(mProvidedPrincipal)) {
       return NS_OK;
     }
   }
 
+  // Deserialize the structured clone data
   JS::Rooted<JS::Value> messageData(cx);
-  nsCOMPtr<nsPIDOMWindow> window = targetWindow.get();
-  if (!Read(window, cx, &messageData)) {
+  StructuredCloneInfo scInfo;
+  scInfo.event = this;
+  scInfo.window = targetWindow;
+
+  if (!mBuffer.read(cx, &messageData, &sPostMessageCallbacks, &scInfo)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   // Create the event
   nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
     do_QueryInterface(static_cast<nsPIDOMWindow*>(targetWindow.get()));
   nsRefPtr<MessageEvent> event =
     new MessageEvent(eventTarget, nullptr, nullptr);
 
   event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */,
                           false /*cancelable */, messageData, mCallerOrigin,
                           EmptyString(), mSource);
 
   event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
-                                      GetTransferredPorts()));
+                                      scInfo.clonedPorts));
 
   // We can't simply call dispatchEvent on the window because doing so ends
   // up flipping the trusted bit on the event, and we don't want that to
   // happen because then untrusted content can call postMessage on a chrome
   // window if it can get a reference to it.
 
   nsIPresShell *shell = targetWindow->GetExtantDoc()->GetShell();
   nsRefPtr<nsPresContext> presContext;
@@ -129,10 +387,24 @@ PostMessageEvent::Run()
   EventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
                             presContext,
                             internalEvent,
                             static_cast<dom::Event*>(event.get()),
                             &status);
   return NS_OK;
 }
 
+bool
+PostMessageEvent::Write(JSContext* aCx, JS::Handle<JS::Value> aMessage,
+                        JS::Handle<JS::Value> aTransfer, nsPIDOMWindow* aWindow)
+{
+  // We *must* clone the data here, or the JS::Value could be modified
+  // by script
+  StructuredCloneInfo scInfo;
+  scInfo.event = this;
+  scInfo.window = aWindow;
+
+  return mBuffer.write(aCx, aMessage, aTransfer, &sPostMessageCallbacks,
+                       &scInfo);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/PostMessageEvent.h
+++ b/dom/base/PostMessageEvent.h
@@ -2,17 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PostMessageEvent_h
 #define mozilla_dom_PostMessageEvent_h
 
-#include "mozilla/dom/StructuredCloneHelper.h"
+#include "js/StructuredClone.h"
 #include "nsCOMPtr.h"
 #include "nsRefPtr.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 
 class nsGlobalWindow;
 class nsIPrincipal;
 class nsPIDOMWindow;
@@ -23,33 +23,87 @@ namespace dom {
 class MessagePortBase;
 class MessagePortIdentifier;
 
 /**
  * Class used to represent events generated by calls to Window.postMessage,
  * which asynchronously creates and dispatches events.
  */
 class PostMessageEvent final : public nsRunnable
-                             , public StructuredCloneHelper
 {
 public:
   NS_DECL_NSIRUNNABLE
 
   PostMessageEvent(nsGlobalWindow* aSource,
                    const nsAString& aCallerOrigin,
                    nsGlobalWindow* aTargetWindow,
                    nsIPrincipal* aProvidedPrincipal,
                    bool aTrustedCaller);
 
+  bool Write(JSContext* aCx, JS::Handle<JS::Value> aMessage,
+             JS::Handle<JS::Value> aTransfer, nsPIDOMWindow* aWindow);
+
 private:
   ~PostMessageEvent();
 
+  const MessagePortIdentifier& GetPortIdentifier(uint64_t aId);
+
+  MessagePortIdentifier* NewPortIdentifier(uint64_t* aPosition);
+
+  bool StoreISupports(nsISupports* aSupports)
+  {
+    mSupportsArray.AppendElement(aSupports);
+    return true;
+  }
+
+  static JSObject*
+  ReadStructuredClone(JSContext* cx,
+                      JSStructuredCloneReader* reader,
+                      uint32_t tag,
+                      uint32_t data,
+                      void* closure);
+
+  static bool
+  WriteStructuredClone(JSContext* cx,
+                       JSStructuredCloneWriter* writer,
+                       JS::Handle<JSObject*> obj,
+                       void *closure);
+
+  static bool
+  ReadTransferStructuredClone(JSContext* aCx,
+                              JSStructuredCloneReader* reader,
+                              uint32_t tag, void* aData,
+                              uint64_t aExtraData,
+                              void* aClosure,
+                              JS::MutableHandle<JSObject*> returnObject);
+
+  static bool
+  TransferStructuredClone(JSContext* aCx,
+                          JS::Handle<JSObject*> aObj,
+                          void* aClosure,
+                          uint32_t* aTag,
+                          JS::TransferableOwnership* aOwnership,
+                          void** aContent,
+                          uint64_t* aExtraData);
+
+  static void
+  FreeTransferStructuredClone(uint32_t aTag,
+                              JS::TransferableOwnership aOwnership,
+                              void *aContent,
+                              uint64_t aExtraData,
+                              void* aClosure);
+
+  static const JSStructuredCloneCallbacks sPostMessageCallbacks;
+
+  JSAutoStructuredCloneBuffer mBuffer;
   nsRefPtr<nsGlobalWindow> mSource;
   nsString mCallerOrigin;
   nsRefPtr<nsGlobalWindow> mTargetWindow;
   nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
   bool mTrustedCaller;
+  nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
+  nsTArray<MessagePortIdentifier> mPortIdentifiers;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PostMessageEvent_h
--- a/dom/base/StructuredCloneHelper.cpp
+++ b/dom/base/StructuredCloneHelper.cpp
@@ -1,20 +1,16 @@
 /* -*- 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 "StructuredCloneHelper.h"
 
-#include "mozilla/dom/BlobBinding.h"
-#include "mozilla/dom/FileListBinding.h"
-#include "mozilla/dom/StructuredCloneTags.h"
-
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 JSObject*
 StructuredCloneCallbacksRead(JSContext* aCx,
                              JSStructuredCloneReader* aReader,
@@ -98,40 +94,27 @@ const JSStructuredCloneCallbacks gCallba
   StructuredCloneCallbacksError,
   StructuredCloneCallbacksReadTransfer,
   StructuredCloneCallbacksWriteTransfer,
   StructuredCloneCallbacksFreeTransfer
 };
 
 } // anonymous namespace
 
-// StructuredCloneHelperInternal class
-
 bool
 StructuredCloneHelperInternal::Write(JSContext* aCx,
                                      JS::Handle<JS::Value> aValue)
 {
   MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
 
   mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this);
   return mBuffer->write(aCx, aValue, &gCallbacks, this);
 }
 
 bool
-StructuredCloneHelperInternal::Write(JSContext* aCx,
-                                     JS::Handle<JS::Value> aValue,
-                                     JS::Handle<JS::Value> aTransfer)
-{
-  MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
-
-  mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this);
-  return mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this);
-}
-
-bool
 StructuredCloneHelperInternal::Read(JSContext* aCx,
                                     JS::MutableHandle<JS::Value> aValue)
 {
   MOZ_ASSERT(mBuffer, "Read() without Write() is not allowed.");
 
   bool ok = mBuffer->read(aCx, aValue, &gCallbacks, this);
   mBuffer = nullptr;
   return ok;
@@ -144,16 +127,17 @@ StructuredCloneHelperInternal::ReadTrans
                                                     void* aContent,
                                                     uint64_t aExtraData,
                                                     JS::MutableHandleObject aReturnObject)
 {
   MOZ_CRASH("Nothing to read.");
   return false;
 }
 
+
 bool
 StructuredCloneHelperInternal::WriteTransferCallback(JSContext* aCx,
                                                      JS::Handle<JSObject*> aObj,
                                                      uint32_t* aTag,
                                                      JS::TransferableOwnership* aOwnership,
                                                      void** aContent,
                                                      uint64_t* aExtraData)
 {
@@ -165,225 +149,10 @@ void
 StructuredCloneHelperInternal::FreeTransferCallback(uint32_t aTag,
                                                     JS::TransferableOwnership aOwnership,
                                                     void* aContent,
                                                     uint64_t aExtraData)
 {
   MOZ_CRASH("Nothing to free.");
 }
 
-// StructuredCloneHelper class
-
-StructuredCloneHelper::StructuredCloneHelper(uint32_t aFlags)
-  : mFlags(aFlags)
-  , mParent(nullptr)
-{}
-
-StructuredCloneHelper::~StructuredCloneHelper()
-{}
-
-bool
-StructuredCloneHelper::Write(JSContext* aCx,
-                             JS::Handle<JS::Value> aValue,
-                             JS::Handle<JS::Value> aTransfer)
-{
-  bool ok = StructuredCloneHelperInternal::Write(aCx, aValue, aTransfer);
-  mTransferringPort.Clear();
-  return ok;
-}
-
-bool
-StructuredCloneHelper::Read(nsISupports* aParent,
-                            JSContext* aCx,
-                            JS::MutableHandle<JS::Value> aValue)
-{
-  mozilla::AutoRestore<nsISupports*> guard(mParent);
-  mParent = aParent;
-
-  return StructuredCloneHelperInternal::Read(aCx, aValue);
-}
-
-JSObject*
-StructuredCloneHelper::ReadCallback(JSContext* aCx,
-                                    JSStructuredCloneReader* aReader,
-                                    uint32_t aTag,
-                                    uint32_t aIndex)
-{
-  if (aTag == SCTAG_DOM_BLOB) {
-    MOZ_ASSERT(!(mFlags & eBlobNotSupported));
-
-    BlobImpl* blobImpl;
-    if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
-      MOZ_ASSERT(blobImpl);
-
-      // 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);
-      {
-        nsRefPtr<Blob> blob = Blob::Create(mParent, blobImpl);
-        if (!ToJSValue(aCx, blob, &val)) {
-          return nullptr;
-        }
-      }
-
-      return &val.toObject();
-    }
-  }
-
-  if (aTag == SCTAG_DOM_FILELIST) {
-    MOZ_ASSERT(!(mFlags & eFileListNotSupported));
-
-    FileListClonedData* fileListClonedData;
-    if (JS_ReadBytes(aReader, &fileListClonedData,
-                     sizeof(fileListClonedData))) {
-      MOZ_ASSERT(fileListClonedData);
-
-      // nsRefPtr<FileList> 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);
-      {
-        nsRefPtr<FileList> fileList =
-          FileList::Create(mParent, fileListClonedData);
-        if (!fileList || !ToJSValue(aCx, fileList, &val)) {
-          return nullptr;
-        }
-      }
-
-      return &val.toObject();
-    }
-  }
-
-  return NS_DOMReadStructuredClone(aCx, aReader, aTag, aIndex, nullptr);
-}
-
-bool
-StructuredCloneHelper::WriteCallback(JSContext* aCx,
-                                     JSStructuredCloneWriter* aWriter,
-                                     JS::Handle<JSObject*> aObj)
-{
-  // See if this is a File/Blob object.
-  if (!(mFlags & eBlobNotSupported)) {
-    Blob* blob = nullptr;
-    if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
-      BlobImpl* blobImpl = blob->Impl();
-      return JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, 0) &&
-             JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl)) &&
-             StoreISupports(blobImpl);
-    }
-  }
-
-  if (!(mFlags & eFileListNotSupported)) {
-    FileList* fileList = nullptr;
-    if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
-      nsRefPtr<FileListClonedData> fileListClonedData =
-        fileList->CreateClonedData();
-      MOZ_ASSERT(fileListClonedData);
-      FileListClonedData* ptr = fileListClonedData.get();
-      return JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST, 0) &&
-             JS_WriteBytes(aWriter, &ptr, sizeof(ptr)) &&
-             StoreISupports(fileListClonedData);
-    }
-  }
-
-  return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
-}
-
-bool
-StructuredCloneHelper::ReadTransferCallback(JSContext* aCx,
-                                            JSStructuredCloneReader* aReader,
-                                            uint32_t aTag,
-                                            void* aContent,
-                                            uint64_t aExtraData,
-                                            JS::MutableHandleObject aReturnObject)
-{
-  if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
-    MOZ_ASSERT(!(mFlags & eMessagePortNotSupported));
-
-    // This can be null.
-    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mParent);
-
-    MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
-    const MessagePortIdentifier& portIdentifier = mPortIdentifiers[aExtraData];
-
-    // aExtraData is the index of this port identifier.
-    ErrorResult rv;
-    nsRefPtr<MessagePort> port =
-      MessagePort::Create(window, portIdentifier, rv);
-    if (NS_WARN_IF(rv.Failed())) {
-      return false;
-    }
-
-    mTransferredPorts.AppendElement(port);
-
-    JS::Rooted<JS::Value> value(aCx);
-    if (!GetOrCreateDOMReflector(aCx, port, &value)) {
-      JS_ClearPendingException(aCx);
-      return false;
-    }
-
-    aReturnObject.set(&value.toObject());
-    return true;
-  }
-
-  return false;
-}
-
-
-bool
-StructuredCloneHelper::WriteTransferCallback(JSContext* aCx,
-                                             JS::Handle<JSObject*> aObj,
-                                             uint32_t* aTag,
-                                             JS::TransferableOwnership* aOwnership,
-                                             void** aContent,
-                                             uint64_t* aExtraData)
-{
-  if (!(mFlags & eMessagePortNotSupported)) {
-    MessagePortBase* port = nullptr;
-    nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
-    if (NS_SUCCEEDED(rv)) {
-      if (mTransferringPort.Contains(port)) {
-        // No duplicates.
-        return false;
-      }
-
-      // We use aExtraData to store the index of this new port identifier.
-      *aExtraData = mPortIdentifiers.Length();
-      MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement();
-
-      if (!port->CloneAndDisentangle(*identifier)) {
-        return false;
-      }
-
-      mTransferringPort.AppendElement(port);
-
-      *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
-      *aOwnership = JS::SCTAG_TMO_CUSTOM;
-      *aContent = nullptr;
-
-      return true;
-    }
-  }
-
-  return false;
-}
-
-void
-StructuredCloneHelper::FreeTransferCallback(uint32_t aTag,
-                                            JS::TransferableOwnership aOwnership,
-                                            void* aContent,
-                                            uint64_t aExtraData)
-{
-  if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
-    MOZ_ASSERT(!(mFlags & eMessagePortNotSupported));
-    MOZ_ASSERT(!aContent);
-    MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
-    MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
-  }
-}
-
 } // dom namespace
 } // mozilla namespace
--- a/dom/base/StructuredCloneHelper.h
+++ b/dom/base/StructuredCloneHelper.h
@@ -3,18 +3,16 @@
  * 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_StructuredCloneHelper_h
 #define mozilla_dom_StructuredCloneHelper_h
 
 #include "js/StructuredClone.h"
 #include "nsAutoPtr.h"
-#include "nsISupports.h"
-#include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 
 class StructuredCloneHelperInternal
 {
 public:
   // These methods should be implemented in order to clone data.
@@ -66,115 +64,12 @@ public:
 
   bool Read(JSContext* aCx,
             JS::MutableHandle<JS::Value> aValue);
 
 protected:
   nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
 };
 
-class MessagePortBase;
-class MessagePortIdentifier;
-
-class StructuredCloneHelper : public StructuredCloneHelperInternal
-{
-public:
-  enum StructuredCloneHelperFlags {
-    eAll = 0,
-
-    // Disable the cloning of blobs. If a blob is part of the cloning value,
-    // an exception will be thrown.
-    eBlobNotSupported = 1 << 0,
-
-    // Disable the cloning of FileLists. If a FileList is part of the cloning
-    // value, an exception will be thrown.
-    eFileListNotSupported = 1 << 1,
-
-    // MessagePort can just be transfered. Using this flag we do not support
-    // the transfering.
-    eMessagePortNotSupported = 1 << 2,
-  };
-
-  // aFlags is a bitmap of StructuredCloneHelperFlags.
-  explicit StructuredCloneHelper(uint32_t aFlags = eAll);
-  virtual ~StructuredCloneHelper();
-
-  bool Write(JSContext* aCx,
-             JS::Handle<JS::Value> aValue,
-             JS::Handle<JS::Value> aTransfer);
-
-  bool Read(nsISupports* aParent,
-            JSContext* aCx,
-            JS::MutableHandle<JS::Value> aValue);
-
-  nsTArray<nsRefPtr<MessagePortBase>>& GetTransferredPorts()
-  {
-    MOZ_ASSERT(!(mFlags & eMessagePortNotSupported));
-    return mTransferredPorts;
-  }
-
-  // Custom Callbacks
-
-  virtual JSObject* ReadCallback(JSContext* aCx,
-                                 JSStructuredCloneReader* aReader,
-                                 uint32_t aTag,
-                                 uint32_t aIndex) override;
-
-  virtual bool WriteCallback(JSContext* aCx,
-                             JSStructuredCloneWriter* aWriter,
-                             JS::Handle<JSObject*> aObj) override;
-
-  virtual bool ReadTransferCallback(JSContext* aCx,
-                                    JSStructuredCloneReader* aReader,
-                                    uint32_t aTag,
-                                    void* aContent,
-                                    uint64_t aExtraData,
-                                    JS::MutableHandleObject aReturnObject) override;
-
-  virtual bool WriteTransferCallback(JSContext* aCx,
-                                     JS::Handle<JSObject*> aObj,
-                                     uint32_t* aTag,
-                                     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:
-  bool StoreISupports(nsISupports* aSupports)
-  {
-    MOZ_ASSERT(aSupports);
-    mSupportsArray.AppendElement(aSupports);
-    return true;
-  }
-
-  // This is our bitmap.
-  uint32_t mFlags;
-
-  // Useful for the structured clone algorithm:
-
-  nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
-
-  // This raw pointer is set and unset into the ::Read(). It's always null
-  // outside that method. For this reason it's a raw pointer.
-  nsISupports* MOZ_NON_OWNING_REF mParent;
-
-  // This hashtable contains the ports while doing write (transferring and
-  // mapping transferred objects to the objects in the clone). It's an empty
-  // array outside the 'Write()' method.
-  nsTArray<nsRefPtr<MessagePortBase>> mTransferringPort;
-
-  // 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;
-};
-
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_StructuredCloneHelper_h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8559,17 +8559,17 @@ nsGlobalWindow::PostMessageMozOuter(JSCo
                          origin,
                          this,
                          providedPrincipal,
                          nsContentUtils::IsCallerChrome());
 
   JS::Rooted<JS::Value> message(aCx, aMessage);
   JS::Rooted<JS::Value> transfer(aCx, aTransfer);
 
-  if (!event->Write(aCx, message, transfer)) {
+  if (!event->Write(aCx, message, transfer, this)) {
     aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
     return;
   }
 
   aError = NS_DispatchToCurrentThread(event);
 }
 
 void