Bug 1203916 - Get rid of NS_DOMReadStructuredClone and NS_DOMWriteStructuredClone, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 15 Sep 2015 01:05:44 +0800
changeset 294988 db888b35735375727a820567d3cac8bef4baa25f
parent 294987 01d3a641203f970a446948634b9dbb6f36fb5908
child 294989 71a37a05fc1d1756d8fa86450bd7336fdc1a7bef
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1203916
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1203916 - Get rid of NS_DOMReadStructuredClone and NS_DOMWriteStructuredClone, r=smaug
dom/base/StructuredCloneHelper.cpp
dom/base/StructuredCloneHelper.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
dom/indexedDB/IDBObjectStore.cpp
--- a/dom/base/StructuredCloneHelper.cpp
+++ b/dom/base/StructuredCloneHelper.cpp
@@ -4,38 +4,49 @@
  * 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 "ImageContainer.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/CryptoKey.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileList.h"
 #include "mozilla/dom/FileListBinding.h"
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/ImageBitmapBinding.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ImageDataBinding.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/StructuredClone.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/PMessagePort.h"
 #include "mozilla/dom/StructuredCloneTags.h"
+#include "mozilla/dom/SubtleCryptoBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/WebCryptoCommon.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
+#include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "MultipartBlobImpl.h"
 #include "nsFormData.h"
 #include "nsIRemoteBlob.h"
 #include "nsQueryObject.h"
 
+#ifdef MOZ_NFC
+#include "mozilla/dom/MozNDEFRecord.h"
+#endif // MOZ_NFC
+#ifdef MOZ_WEBRTC
+#include "mozilla/dom/RTCCertificate.h"
+#include "mozilla/dom/RTCCertificateBinding.h"
+#endif
+
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 JSObject*
@@ -363,16 +374,227 @@ StructuredCloneHelper::FreeBuffer(uint64
 {
   MOZ_ASSERT(!mBuffer, "FreeBuffer() must be called without a Write().");
   MOZ_ASSERT(aBuffer);
   MOZ_ASSERT(aBufferLength);
 
   JS_ClearStructuredClone(aBuffer, aBufferLength, &gCallbacks, this, false);
 }
 
+/* static */ JSObject*
+StructuredCloneHelper::ReadFullySerializableObjects(JSContext* aCx,
+                                                    JSStructuredCloneReader* aReader,
+                                                    uint32_t aTag,
+                                                    uint32_t aIndex)
+{
+  if (aTag == SCTAG_DOM_IMAGEDATA) {
+    return ReadStructuredCloneImageData(aCx, aReader);
+  }
+
+  if (aTag == SCTAG_DOM_WEBCRYPTO_KEY) {
+    if (!NS_IsMainThread()) {
+      return nullptr;
+    }
+
+    nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
+    if (!global) {
+      return nullptr;
+    }
+
+    // Prevent the return value from being trashed by a GC during ~nsRefPtr.
+    JS::Rooted<JSObject*> result(aCx);
+    {
+      nsRefPtr<CryptoKey> key = new CryptoKey(global);
+      if (!key->ReadStructuredClone(aReader)) {
+        result = nullptr;
+      } else {
+        result = key->WrapObject(aCx, nullptr);
+      }
+    }
+    return result;
+  }
+
+  if (aTag == SCTAG_DOM_NULL_PRINCIPAL ||
+      aTag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
+      aTag == SCTAG_DOM_CONTENT_PRINCIPAL) {
+    if (!NS_IsMainThread()) {
+      return nullptr;
+    }
+
+    mozilla::ipc::PrincipalInfo info;
+    if (aTag == SCTAG_DOM_SYSTEM_PRINCIPAL) {
+      info = mozilla::ipc::SystemPrincipalInfo();
+    } else if (aTag == SCTAG_DOM_NULL_PRINCIPAL) {
+      info = mozilla::ipc::NullPrincipalInfo();
+    } else {
+      uint32_t appId = aIndex;
+
+      uint32_t isInBrowserElement, specLength;
+      if (!JS_ReadUint32Pair(aReader, &isInBrowserElement, &specLength)) {
+        return nullptr;
+      }
+
+      nsAutoCString spec;
+      spec.SetLength(specLength);
+      if (!JS_ReadBytes(aReader, spec.BeginWriting(), specLength)) {
+        return nullptr;
+      }
+
+      info = mozilla::ipc::ContentPrincipalInfo(appId, isInBrowserElement,
+                                                spec);
+    }
+
+    nsresult rv;
+    nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(info, &rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
+      return nullptr;
+    }
+
+    JS::RootedValue result(aCx);
+    rv = nsContentUtils::WrapNative(aCx, principal, &NS_GET_IID(nsIPrincipal),
+                                    &result);
+    if (NS_FAILED(rv)) {
+      xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
+      return nullptr;
+    }
+
+    return result.toObjectOrNull();
+  }
+
+#ifdef MOZ_NFC
+  if (aTag == SCTAG_DOM_NFC_NDEF) {
+    if (!NS_IsMainThread()) {
+      return nullptr;
+    }
+
+    nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
+    if (!global) {
+      return nullptr;
+    }
+
+    // Prevent the return value from being trashed by a GC during ~nsRefPtr.
+    JS::Rooted<JSObject*> result(aCx);
+    {
+      nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(global);
+      result = ndefRecord->ReadStructuredClone(aCx, aReader) ?
+               ndefRecord->WrapObject(aCx, nullptr) : nullptr;
+    }
+    return result;
+  }
+#endif
+
+#ifdef MOZ_WEBRTC
+  if (aTag == SCTAG_DOM_RTC_CERTIFICATE) {
+    if (!NS_IsMainThread()) {
+      return nullptr;
+    }
+
+    nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
+    if (!global) {
+      return nullptr;
+    }
+
+    // Prevent the return value from being trashed by a GC during ~nsRefPtr.
+    JS::Rooted<JSObject*> result(aCx);
+    {
+      nsRefPtr<RTCCertificate> cert = new RTCCertificate(global);
+      if (!cert->ReadStructuredClone(aReader)) {
+        result = nullptr;
+      } else {
+        result = cert->WrapObject(aCx, nullptr);
+      }
+    }
+    return result;
+  }
+#endif
+
+  // Don't know what this is. Bail.
+  xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
+  return nullptr;
+}
+
+/* static */ bool
+StructuredCloneHelper::WriteFullySerializableObjects(JSContext* aCx,
+                                                     JSStructuredCloneWriter* aWriter,
+                                                     JS::Handle<JSObject*> aObj)
+{
+  // See if this is a ImageData object.
+  {
+    ImageData* imageData = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, aObj, imageData))) {
+      return WriteStructuredCloneImageData(aCx, aWriter, imageData);
+    }
+  }
+
+  // Handle Key cloning
+  {
+    CryptoKey* key;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(CryptoKey, aObj, key))) {
+      MOZ_ASSERT(NS_IsMainThread());
+      return JS_WriteUint32Pair(aWriter, SCTAG_DOM_WEBCRYPTO_KEY, 0) &&
+             key->WriteStructuredClone(aWriter);
+    }
+  }
+
+#ifdef MOZ_WEBRTC
+  {
+    // Handle WebRTC Certificate cloning
+    RTCCertificate* cert;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(RTCCertificate, aObj, cert))) {
+      MOZ_ASSERT(NS_IsMainThread());
+      return JS_WriteUint32Pair(aWriter, SCTAG_DOM_RTC_CERTIFICATE, 0) &&
+             cert->WriteStructuredClone(aWriter);
+    }
+  }
+#endif
+
+  if (NS_IsMainThread() && xpc::IsReflector(aObj)) {
+    nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(aObj);
+    nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(base);
+    if (principal) {
+      mozilla::ipc::PrincipalInfo info;
+      if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(principal, &info)))) {
+        xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
+        return false;
+      }
+
+      if (info.type() == mozilla::ipc::PrincipalInfo::TNullPrincipalInfo) {
+        return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NULL_PRINCIPAL, 0);
+      }
+      if (info.type() == mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) {
+        return JS_WriteUint32Pair(aWriter, SCTAG_DOM_SYSTEM_PRINCIPAL, 0);
+      }
+
+      MOZ_ASSERT(info.type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
+      const mozilla::ipc::ContentPrincipalInfo& cInfo = info;
+      return JS_WriteUint32Pair(aWriter, SCTAG_DOM_CONTENT_PRINCIPAL,
+                                cInfo.appId()) &&
+             JS_WriteUint32Pair(aWriter, cInfo.isInBrowserElement(),
+                                cInfo.spec().Length()) &&
+             JS_WriteBytes(aWriter, cInfo.spec().get(), cInfo.spec().Length());
+    }
+  }
+
+#ifdef MOZ_NFC
+  {
+    MozNDEFRecord* ndefRecord;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(MozNDEFRecord, aObj, ndefRecord))) {
+      MOZ_ASSERT(NS_IsMainThread());
+      return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NFC_NDEF, 0) &&
+             ndefRecord->WriteStructuredClone(aCx, aWriter);
+    }
+  }
+#endif // MOZ_NFC
+
+  // Don't know what this is
+  xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
+  return false;
+}
+
 namespace {
 
 // Recursive!
 already_AddRefed<BlobImpl>
 EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
                                PBackgroundChild* aManager = nullptr)
 {
   MOZ_ASSERT(aBlobImpl);
@@ -726,37 +948,33 @@ StructuredCloneHelper::ReadCallback(JSCo
   if (aTag == SCTAG_DOM_BLOB) {
     return ReadBlob(aCx, aIndex, this);
   }
 
   if (aTag == SCTAG_DOM_FILELIST) {
     return ReadFileList(aCx, aReader, aIndex, this);
   }
 
-  if (aTag == SCTAG_DOM_IMAGEDATA) {
-    return ReadStructuredCloneImageData(aCx, aReader);
-  }
-
   if (aTag == SCTAG_DOM_FORMDATA) {
     return ReadFormData(aCx, aReader, aIndex, this);
   }
 
   if (aTag == SCTAG_DOM_IMAGEBITMAP) {
     MOZ_ASSERT(mContext == SameProcessSameThread ||
                mContext == SameProcessDifferentThread);
 
-     // Get the current global object.
-     // This can be null.
-     nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(mParent);
-     // aIndex is the index of the cloned image.
-     return ImageBitmap::ReadStructuredClone(aCx, aReader,
-                                             parent, GetImages(), aIndex);
+    // Get the current global object.
+    // This can be null.
+    nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(mParent);
+    // aIndex is the index of the cloned image.
+    return ImageBitmap::ReadStructuredClone(aCx, aReader,
+                                            parent, GetImages(), aIndex);
    }
 
-  return NS_DOMReadStructuredClone(aCx, aReader, aTag, aIndex, nullptr);
+  return ReadFullySerializableObjects(aCx, aReader, aTag, aIndex);
 }
 
 bool
 StructuredCloneHelper::WriteCallback(JSContext* aCx,
                                      JSStructuredCloneWriter* aWriter,
                                      JS::Handle<JSObject*> aObj)
 {
   if (!mSupportsCloning) {
@@ -774,24 +992,16 @@ StructuredCloneHelper::WriteCallback(JSC
   // See if this is a FileList object.
   {
     FileList* fileList = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
       return WriteFileList(aWriter, fileList, this);
     }
   }
 
-  // See if this is a ImageData object.
-  {
-    ImageData* imageData = nullptr;
-    if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, aObj, imageData))) {
-      return WriteStructuredCloneImageData(aCx, aWriter, imageData);
-    }
-  }
-
   // See if this is a FormData object.
   {
     nsFormData* formData = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
       return WriteFormData(aWriter, formData, this);
     }
   }
 
@@ -801,17 +1011,17 @@ StructuredCloneHelper::WriteCallback(JSC
     ImageBitmap* imageBitmap = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) {
       return ImageBitmap::WriteStructuredClone(aWriter,
                                                GetImages(),
                                                imageBitmap);
     }
   }
 
-  return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
+  return WriteFullySerializableObjects(aCx, aWriter, aObj);
 }
 
 bool
 StructuredCloneHelper::ReadTransferCallback(JSContext* aCx,
                                             JSStructuredCloneReader* aReader,
                                             uint32_t aTag,
                                             void* aContent,
                                             uint64_t aExtraData,
--- a/dom/base/StructuredCloneHelper.h
+++ b/dom/base/StructuredCloneHelper.h
@@ -233,16 +233,26 @@ public:
                                      JS::TransferableOwnership* aOwnership,
                                      void** aContent,
                                      uint64_t* aExtraData) override;
 
   virtual void FreeTransferCallback(uint32_t aTag,
                                     JS::TransferableOwnership aOwnership,
                                     void* aContent,
                                     uint64_t aExtraData) override;
+
+  static JSObject* ReadFullySerializableObjects(JSContext* aCx,
+                                                JSStructuredCloneReader* aReader,
+                                                uint32_t aTag,
+                                                uint32_t aIndex);
+
+  static bool  WriteFullySerializableObjects(JSContext* aCx,
+                                             JSStructuredCloneWriter* aWriter,
+                                             JS::Handle<JSObject*> aObj);
+
 protected:
   // If you receive a buffer from IPC, you can use this method to retrieve a
   // JS::Value. It can happen that you want to pre-populate the array of Blobs
   // and/or the PortIdentifiers.
   void ReadFromBuffer(nsISupports* aParent,
                       JSContext* aCx,
                       uint64_t* aBuffer,
                       size_t aBufferLength,
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -46,33 +46,18 @@
 #include "js/SliceBudget.h"
 #include "nsIArray.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "prmem.h"
 #include "WrapperFactory.h"
 #include "nsGlobalWindow.h"
 #include "nsScriptNameSpaceManager.h"
-#include "StructuredCloneTags.h"
 #include "mozilla/AutoRestore.h"
-#include "mozilla/dom/CryptoKey.h"
 #include "mozilla/dom/ErrorEvent.h"
-#include "mozilla/dom/ImageDataBinding.h"
-#include "mozilla/dom/ImageData.h"
-#ifdef MOZ_NFC
-#include "mozilla/dom/MozNDEFRecord.h"
-#endif // MOZ_NFC
-#ifdef MOZ_WEBRTC
-#include "mozilla/dom/RTCCertificate.h"
-#include "mozilla/dom/RTCCertificateBinding.h"
-#endif
-#include "mozilla/dom/StructuredClone.h"
-#include "mozilla/dom/SubtleCryptoBinding.h"
-#include "mozilla/ipc/BackgroundUtils.h"
-#include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "nsAXPCNativeCallContext.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 
 #include "nsJSPrincipals.h"
 
 #ifdef XP_MACOSX
 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
 #undef check
@@ -2480,225 +2465,16 @@ SetMemoryGCDynamicMarkSlicePrefChangedCa
 
 static void
 SetIncrementalCCPrefChangedCallback(const char* aPrefName, void* aClosure)
 {
   bool pref = Preferences::GetBool(aPrefName);
   sIncrementalCC = pref;
 }
 
-JSObject*
-NS_DOMReadStructuredClone(JSContext* cx,
-                          JSStructuredCloneReader* reader,
-                          uint32_t tag,
-                          uint32_t data,
-                          void* closure)
-{
-  if (tag == SCTAG_DOM_IMAGEDATA) {
-    return ReadStructuredCloneImageData(cx, reader);
-  }
-
-  if (tag == SCTAG_DOM_WEBCRYPTO_KEY) {
-    if (!NS_IsMainThread()) {
-      return nullptr;
-    }
-
-    nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
-    if (!global) {
-      return nullptr;
-    }
-
-    // Prevent the return value from being trashed by a GC during ~nsRefPtr.
-    JS::Rooted<JSObject*> result(cx);
-    {
-      nsRefPtr<CryptoKey> key = new CryptoKey(global);
-      if (!key->ReadStructuredClone(reader)) {
-        result = nullptr;
-      } else {
-        result = key->WrapObject(cx, nullptr);
-      }
-    }
-    return result;
-  }
-
-  if (tag == SCTAG_DOM_NULL_PRINCIPAL ||
-      tag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
-      tag == SCTAG_DOM_CONTENT_PRINCIPAL) {
-    if (!NS_IsMainThread()) {
-      return nullptr;
-    }
-
-    mozilla::ipc::PrincipalInfo info;
-    if (tag == SCTAG_DOM_SYSTEM_PRINCIPAL) {
-      info = mozilla::ipc::SystemPrincipalInfo();
-    } else if (tag == SCTAG_DOM_NULL_PRINCIPAL) {
-      info = mozilla::ipc::NullPrincipalInfo();
-    } else {
-      uint32_t appId = data;
-
-      uint32_t isInBrowserElement, specLength;
-      if (!JS_ReadUint32Pair(reader, &isInBrowserElement, &specLength)) {
-        return nullptr;
-      }
-
-      nsAutoCString spec;
-      spec.SetLength(specLength);
-      if (!JS_ReadBytes(reader, spec.BeginWriting(), specLength)) {
-        return nullptr;
-      }
-
-      info = mozilla::ipc::ContentPrincipalInfo(appId, isInBrowserElement, spec);
-    }
-
-    nsresult rv;
-    nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(info, &rv);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      xpc::Throw(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
-      return nullptr;
-    }
-
-    JS::RootedValue result(cx);
-    rv = nsContentUtils::WrapNative(cx, principal, &NS_GET_IID(nsIPrincipal), &result);
-    if (NS_FAILED(rv)) {
-      xpc::Throw(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
-      return nullptr;
-    }
-
-    return result.toObjectOrNull();
-  }
-
-#ifdef MOZ_NFC
-  if (tag == SCTAG_DOM_NFC_NDEF) {
-    if (!NS_IsMainThread()) {
-      return nullptr;
-    }
-
-    nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
-    if (!global) {
-      return nullptr;
-    }
-
-    // Prevent the return value from being trashed by a GC during ~nsRefPtr.
-    JS::Rooted<JSObject*> result(cx);
-    {
-      nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(global);
-      result = ndefRecord->ReadStructuredClone(cx, reader) ?
-               ndefRecord->WrapObject(cx, nullptr) : nullptr;
-    }
-    return result;
-  }
-#endif
-
-#ifdef MOZ_WEBRTC
-  if (tag == SCTAG_DOM_RTC_CERTIFICATE) {
-    if (!NS_IsMainThread()) {
-      return nullptr;
-    }
-
-    nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
-    if (!global) {
-      return nullptr;
-    }
-
-    // Prevent the return value from being trashed by a GC during ~nsRefPtr.
-    JS::Rooted<JSObject*> result(cx);
-    {
-      nsRefPtr<RTCCertificate> cert = new RTCCertificate(global);
-      if (!cert->ReadStructuredClone(reader)) {
-        result = nullptr;
-      } else {
-        result = cert->WrapObject(cx, nullptr);
-      }
-    }
-    return result;
-  }
-#endif
-
-  // Don't know what this is. Bail.
-  xpc::Throw(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
-  return nullptr;
-}
-
-bool
-NS_DOMWriteStructuredClone(JSContext* cx,
-                           JSStructuredCloneWriter* writer,
-                           JS::Handle<JSObject*> obj,
-                           void *closure)
-{
-  // Handle ImageData cloning
-  ImageData* imageData;
-  if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, obj, imageData))) {
-    return WriteStructuredCloneImageData(cx, writer, imageData);
-  }
-
-  // Handle Key cloning
-  CryptoKey* key;
-  if (NS_SUCCEEDED(UNWRAP_OBJECT(CryptoKey, obj, key))) {
-    MOZ_ASSERT(NS_IsMainThread(), "This object should not be exposed outside the main-thread.");
-    return JS_WriteUint32Pair(writer, SCTAG_DOM_WEBCRYPTO_KEY, 0) &&
-           key->WriteStructuredClone(writer);
-  }
-
-#ifdef MOZ_WEBRTC
-  // Handle WebRTC Certificate cloning
-  RTCCertificate* cert;
-  if (NS_SUCCEEDED(UNWRAP_OBJECT(RTCCertificate, obj, cert))) {
-    MOZ_ASSERT(NS_IsMainThread(), "This object should not be exposed outside the main-thread.");
-    return JS_WriteUint32Pair(writer, SCTAG_DOM_RTC_CERTIFICATE, 0) &&
-           cert->WriteStructuredClone(writer);
-  }
-#endif
-
-  if (NS_IsMainThread() && xpc::IsReflector(obj)) {
-    nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(obj);
-    nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(base);
-    if (principal) {
-      mozilla::ipc::PrincipalInfo info;
-      if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(principal, &info)))) {
-        xpc::Throw(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
-        return false;
-      }
-
-      if (info.type() == mozilla::ipc::PrincipalInfo::TNullPrincipalInfo) {
-        return JS_WriteUint32Pair(writer, SCTAG_DOM_NULL_PRINCIPAL, 0);
-      }
-      if (info.type() == mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) {
-        return JS_WriteUint32Pair(writer, SCTAG_DOM_SYSTEM_PRINCIPAL, 0);
-      }
-
-      MOZ_ASSERT(info.type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
-      const mozilla::ipc::ContentPrincipalInfo& cInfo = info;
-      return JS_WriteUint32Pair(writer, SCTAG_DOM_CONTENT_PRINCIPAL, cInfo.appId()) &&
-             JS_WriteUint32Pair(writer, cInfo.isInBrowserElement(), cInfo.spec().Length()) &&
-             JS_WriteBytes(writer, cInfo.spec().get(), cInfo.spec().Length());
-    }
-  }
-
-#ifdef MOZ_NFC
-  MozNDEFRecord* ndefRecord;
-  if (NS_SUCCEEDED(UNWRAP_OBJECT(MozNDEFRecord, obj, ndefRecord))) {
-    MOZ_ASSERT(NS_IsMainThread(), "This object should not be exposed outside the main-thread.");
-    return JS_WriteUint32Pair(writer, SCTAG_DOM_NFC_NDEF, 0) &&
-           ndefRecord->WriteStructuredClone(cx, writer);
-  }
-#endif // MOZ_NFC
-
-  // Don't know what this is
-  xpc::Throw(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
-  return false;
-}
-
-void
-NS_DOMStructuredCloneError(JSContext* cx,
-                           uint32_t errorid)
-{
-  // We don't currently support any extensions to structured cloning.
-  xpc::Throw(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
-}
-
 static bool
 AsmJSCacheOpenEntryForRead(JS::Handle<JSObject*> aGlobal,
                            const char16_t* aBegin,
                            const char16_t* aLimit,
                            size_t* aSize,
                            const uint8_t** aMemory,
                            intptr_t *aHandle)
 {
@@ -2746,27 +2522,16 @@ nsJSContext::EnsureStatics()
     MOZ_CRASH();
   }
 
   // Let's make sure that our main thread is the same as the xpcom main thread.
   MOZ_ASSERT(NS_IsMainThread());
 
   sPrevGCSliceCallback = JS::SetGCSliceCallback(sRuntime, DOMGCSliceCallback);
 
-  // Set up the structured clone callbacks.
-  static const JSStructuredCloneCallbacks cloneCallbacks = {
-    NS_DOMReadStructuredClone,
-    NS_DOMWriteStructuredClone,
-    NS_DOMStructuredCloneError,
-    nullptr,
-    nullptr,
-    nullptr
-  };
-  JS_SetStructuredCloneCallbacks(sRuntime, &cloneCallbacks);
-
   // Set up the asm.js cache callbacks
   static const JS::AsmJSCacheOps asmJSCacheOps = {
     AsmJSCacheOpenEntryForRead,
     asmjscache::CloseEntryForRead,
     AsmJSCacheOpenEntryForWrite,
     asmjscache::CloseEntryForWrite,
     asmjscache::GetBuildId
   };
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -225,19 +225,9 @@ public:
   // Bug 312003 describes why this must be "void **", but after calling argv
   // may be cast to JS::Value* and the args found at:
   //    ((JS::Value*)argv)[0], ..., ((JS::Value*)argv)[argc - 1]
   virtual nsresult GetArgs(uint32_t *argc, void **argv) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSArgArray, NS_IJSARGARRAY_IID)
 
-JSObject* NS_DOMReadStructuredClone(JSContext* cx,
-                                    JSStructuredCloneReader* reader, uint32_t tag,
-                                    uint32_t data, void* closure);
-
-bool NS_DOMWriteStructuredClone(JSContext* cx,
-                                JSStructuredCloneWriter* writer,
-                                JS::Handle<JSObject*> obj, void *closure);
-
-void NS_DOMStructuredCloneError(JSContext* cx, uint32_t errorid);
-
 #endif /* nsJSEnvironment_h */
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -29,16 +29,17 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/IDBMutableFileBinding.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/IDBObjectStoreBinding.h"
+#include "mozilla/dom/StructuredCloneHelper.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/ipc/nsIRemoteBlob.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "nsCOMPtr.h"
@@ -361,24 +362,17 @@ StructuredCloneWriteCallback(JSContext* 
         newBlobOrMutableFile =
           cloneWriteInfo->mBlobOrMutableFiles.AppendElement();
       newBlobOrMutableFile->mBlob = blob;
 
       return true;
     }
   }
 
-  // Try using the runtime callbacks
-  const JSStructuredCloneCallbacks* runtimeCallbacks =
-    js::GetContextStructuredCloneCallbacks(aCx);
-  if (runtimeCallbacks) {
-    return runtimeCallbacks->write(aCx, aWriter, aObj, nullptr);
-  }
-
-  return false;
+  return StructuredCloneHelper::WriteFullySerializableObjects(aCx, aWriter, aObj);
 }
 
 nsresult
 GetAddInfoCallback(JSContext* aCx, void* aClosure)
 {
   static const JSStructuredCloneCallbacks kStructuredCloneCallbacks = {
     nullptr /* read */,
     StructuredCloneWriteCallback /* write */,
@@ -894,24 +888,18 @@ CommonStructuredCloneReadCallback(JSCont
                                                     data,
                                                     &result))) {
       return nullptr;
     }
 
     return result;
   }
 
-  const JSStructuredCloneCallbacks* runtimeCallbacks =
-    js::GetContextStructuredCloneCallbacks(aCx);
-
-  if (runtimeCallbacks) {
-    return runtimeCallbacks->read(aCx, aReader, aTag, aData, nullptr);
-  }
-
-  return nullptr;
+  return StructuredCloneHelper::ReadFullySerializableObjects(aCx, aReader,
+                                                             aTag, aData);
 }
 
 // static
 void
 ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer)
 {
   if (aBuffer.data()) {
     aBuffer.clear();