Backed out changesets 69542d63fcc8 and 6326eaf87f86 (bug 1184557) for causing widespread debug test assertions.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 23 Jul 2015 13:04:14 -0400
changeset 286001 6793c7bd6ea4d792583f83fddacac0a2b831a13a
parent 286000 79637e9bcdaa0657cd79732b095936b377e262b4
child 286002 4c6858eaf1b29c59bdc027b648affbca67c4edc1
push idunknown
push userunknown
push dateunknown
bugs1184557
milestone42.0a1
backs out69542d63fcc858f402992155e870ceec0e350ba4
6326eaf87f8662124a5ad2f7dfce191d925f1b0e
Backed out changesets 69542d63fcc8 and 6326eaf87f86 (bug 1184557) for causing widespread debug test assertions. CLOSED TREE
dom/base/Console.cpp
dom/base/PostMessageEvent.cpp
dom/base/PostMessageEvent.h
dom/base/StructuredCloneHelper.cpp
dom/base/StructuredCloneHelper.h
dom/base/nsGlobalWindow.cpp
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -202,18 +202,16 @@ public:
     , mConsole(aConsole)
   {
     MOZ_ASSERT(mWorkerPrivate);
   }
 
   virtual
   ~ConsoleRunnable()
   {
-    // Shutdown the StructuredCloneHelperInternal class.
-    Shutdown();
   }
 
   bool
   Dispatch()
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
 
     JSContext* cx = mWorkerPrivate->GetJSContext();
--- 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,
@@ -84,85 +80,45 @@ StructuredCloneCallbacksFreeTransfer(uin
   MOZ_ASSERT(helper);
   return helper->FreeTransferCallback(aTag, aOwnership, aContent, aExtraData);
 }
 
 void
 StructuredCloneCallbacksError(JSContext* aCx,
                               uint32_t aErrorId)
 {
-  NS_WARNING("Failed to clone data.");
+  NS_WARNING("Failed to clone data for the Console API in workers.");
 }
 
 const JSStructuredCloneCallbacks gCallbacks = {
   StructuredCloneCallbacksRead,
   StructuredCloneCallbacksWrite,
   StructuredCloneCallbacksError,
   StructuredCloneCallbacksReadTransfer,
   StructuredCloneCallbacksWriteTransfer,
   StructuredCloneCallbacksFreeTransfer
 };
 
 } // anonymous namespace
 
-// StructuredCloneHelperInternal class
-
-StructuredCloneHelperInternal::StructuredCloneHelperInternal()
-#ifdef DEBUG
-  : mShutdownCalled(false)
-#endif
-{}
-
-StructuredCloneHelperInternal::~StructuredCloneHelperInternal()
-{
-#ifdef DEBUG
-  MOZ_ASSERT(mShutdownCalled);
-#endif
-}
-
-void
-StructuredCloneHelperInternal::Shutdown()
-{
-#ifdef DEBUG
-  MOZ_ASSERT(!mShutdownCalled, "Shutdown already called!");
-  mShutdownCalled = true;
-#endif
-
-  mBuffer = nullptr;
-}
-
 bool
 StructuredCloneHelperInternal::Write(JSContext* aCx,
                                      JS::Handle<JS::Value> aValue)
 {
   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, &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");
-  MOZ_ASSERT(mShutdownCalled, "This method cannot be called after Shutdown.");
-
-  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.");
-  MOZ_ASSERT(mShutdownCalled, "This method cannot be called after Shutdown.");
 
   bool ok = mBuffer->read(aCx, aValue, &gCallbacks, this);
   mBuffer = nullptr;
   return ok;
 }
 
 bool
 StructuredCloneHelperInternal::ReadTransferCallback(JSContext* aCx,
@@ -171,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)
 {
@@ -192,227 +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()
-{
-  Shutdown();
-}
-
-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,46 +3,35 @@
  * 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:
-  StructuredCloneHelperInternal();
-  virtual ~StructuredCloneHelperInternal();
-
   // These methods should be implemented in order to clone data.
   // Read more documentation in js/public/StructuredClone.h.
 
   virtual JSObject* ReadCallback(JSContext* aCx,
                                  JSStructuredCloneReader* aReader,
                                  uint32_t aTag,
                                  uint32_t aIndex) = 0;
 
   virtual bool WriteCallback(JSContext* aCx,
                              JSStructuredCloneWriter* aWriter,
                              JS::Handle<JSObject*> aObj) = 0;
 
-  // This method has to be called when this object is not needed anymore.
-  // It will free memory and the buffer. This has to be called because
-  // otherwise the buffer will be freed in the DTOR of this class and at that
-  // point we cannot use the overridden methods.
-  void Shutdown();
-
   // If these 3 methods are not implement, transfering objects will not be
   // allowed.
 
   virtual bool
   ReadTransferCallback(JSContext* aCx,
                        JSStructuredCloneReader* aReader,
                        uint32_t aTag,
                        void* aContent,
@@ -73,121 +62,14 @@ public:
              JS::Handle<JS::Value> aValue,
              JS::Handle<JS::Value> aTransfer);
 
   bool Read(JSContext* aCx,
             JS::MutableHandle<JS::Value> aValue);
 
 protected:
   nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
-
-#ifdef DEBUG
-  bool mShutdownCalled;
-#endif
-};
-
-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
@@ -8577,17 +8577,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