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 287536 9be3d57c2e15cc11be2cb0c427ef231adfa9ce59
parent 287535 01f9844491ce68a93776dab3cafd74789942b2f9
child 287537 1178c11561bced95d152701ce3865b16c4d6d1ed
push id934
push userraliiev@mozilla.com
push dateMon, 26 Oct 2015 12:58:05 +0000
treeherdermozilla-release@05704e35c1d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1184557
milestone42.0a1
backs outf6d29009ae0a599059d750ced11a8654a39fe224
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
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