Bug 1201806 - part 2 - nsStructuredCloneContainer should use StructuredCloneIPCHelper, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 09 Sep 2015 08:11:38 +0100
changeset 294129 0e9db80a50434ad4a913a645c11fba07ddfd7be4
parent 294128 6aa0614b93b8a4cf0d57401655e55208399e07d7
child 294130 63d9b41521e90bb8cef3c2f86c05a274436d9384
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
bugs1201806
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 1201806 - part 2 - nsStructuredCloneContainer should use StructuredCloneIPCHelper, r=smaug
dom/base/StructuredCloneHelper.h
dom/base/nsStructuredCloneContainer.cpp
dom/base/nsStructuredCloneContainer.h
dom/broadcastchannel/BroadcastChannelChild.cpp
dom/ipc/StructuredCloneIPCHelper.cpp
dom/ipc/StructuredCloneIPCHelper.h
--- a/dom/base/StructuredCloneHelper.h
+++ b/dom/base/StructuredCloneHelper.h
@@ -166,38 +166,16 @@ public:
             ErrorResult &aRv);
 
   // Sometimes, when IPC is involved, you must send a buffer after a Write().
   // This method 'steals' the internal data from this helper class.
   // You should free this buffer with FreeBuffer().
   void MoveBufferDataToArray(FallibleTArray<uint8_t>& aArray,
                              ErrorResult& aRv);
 
-  // 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,
-                      JS::MutableHandle<JS::Value> aValue,
-                      ErrorResult &aRv);
-
-  void ReadFromBuffer(nsISupports* aParent,
-                      JSContext* aCx,
-                      uint64_t* aBuffer,
-                      size_t aBufferLength,
-                      uint32_t aAlgorithmVersion,
-                      JS::MutableHandle<JS::Value> aValue,
-                      ErrorResult &aRv);
-
-  // Use this method to free a buffer generated by MoveToBuffer().
-  void FreeBuffer(uint64_t* aBuffer,
-                  size_t aBufferLength);
-
   bool HasClonedDOMObjects() const
   {
     return !mBlobImplArray.IsEmpty() ||
            !mClonedImages.IsEmpty();
   }
 
   nsTArray<nsRefPtr<BlobImpl>>& BlobImpls()
   {
@@ -256,16 +234,38 @@ public:
                                      void** aContent,
                                      uint64_t* aExtraData) override;
 
   virtual void FreeTransferCallback(uint32_t aTag,
                                     JS::TransferableOwnership aOwnership,
                                     void* aContent,
                                     uint64_t aExtraData) override;
 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,
+                      JS::MutableHandle<JS::Value> aValue,
+                      ErrorResult &aRv);
+
+  void ReadFromBuffer(nsISupports* aParent,
+                      JSContext* aCx,
+                      uint64_t* aBuffer,
+                      size_t aBufferLength,
+                      uint32_t aAlgorithmVersion,
+                      JS::MutableHandle<JS::Value> aValue,
+                      ErrorResult &aRv);
+
+  // Use this method to free a buffer generated by MoveToBuffer().
+  void FreeBuffer(uint64_t* aBuffer,
+                  size_t aBufferLength);
+
   bool mSupportsCloning;
   bool mSupportsTransferring;
   ContextSupport mContext;
 
   // Useful for the structured clone algorithm:
 
   nsTArray<nsRefPtr<BlobImpl>> mBlobImplArray;
 
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -11,125 +11,104 @@
 #include "nsIVariant.h"
 #include "nsIXPConnect.h"
 #include "nsServiceManagerUtils.h"
 #include "nsContentUtils.h"
 #include "jsapi.h"
 #include "xpcpublic.h"
 
 #include "mozilla/Base64.h"
-#include "mozilla/dom/StructuredCloneHelper.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_ADDREF(nsStructuredCloneContainer)
 NS_IMPL_RELEASE(nsStructuredCloneContainer)
 
 NS_INTERFACE_MAP_BEGIN(nsStructuredCloneContainer)
   NS_INTERFACE_MAP_ENTRY(nsIStructuredCloneContainer)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 nsStructuredCloneContainer::nsStructuredCloneContainer()
-  : StructuredCloneHelper(CloningSupported, TransferringNotSupported,
-                          DifferentProcess)
-  , mState(eNotInitialized) , mData(nullptr), mSize(0), mVersion(0)
+  : mVersion(0)
 {
 }
 
 nsStructuredCloneContainer::~nsStructuredCloneContainer()
 {
-  if (mData) {
-    free(mData);
-  }
 }
 
 NS_IMETHODIMP
 nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData,
                                           JSContext* aCx)
 {
-  if (mState != eNotInitialized) {
+  if (DataLength()) {
     return NS_ERROR_FAILURE;
   }
 
   ErrorResult rv;
   Write(aCx, aData, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
-  mState = eInitializedFromJSVal;
+  mVersion = JS_STRUCTURED_CLONE_VERSION;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStructuredCloneContainer::InitFromBase64(const nsAString &aData,
                                            uint32_t aFormatVersion,
                                            JSContext* aCx)
 {
-  if (mState != eNotInitialized) {
+  if (DataLength()) {
     return NS_ERROR_FAILURE;
   }
 
   NS_ConvertUTF16toUTF8 data(aData);
 
   nsAutoCString binaryData;
   nsresult rv = Base64Decode(data, binaryData);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Copy the string's data into our own buffer.
-  mData = (uint64_t*) malloc(binaryData.Length());
-  NS_ENSURE_STATE(mData);
-  memcpy(mData, binaryData.get(), binaryData.Length());
+  if (!CopyExternalData(binaryData.get(), binaryData.Length())) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
 
-  mSize = binaryData.Length();
   mVersion = aFormatVersion;
-
-  mState = eInitializedFromBase64;
   return NS_OK;
 }
 
 nsresult
 nsStructuredCloneContainer::DeserializeToJsval(JSContext* aCx,
                                                JS::MutableHandle<JS::Value> aValue)
 {
   aValue.setNull();
   JS::Rooted<JS::Value> jsStateObj(aCx);
 
-  if (mState == eInitializedFromJSVal) {
-    ErrorResult rv;
-    Read(nullptr, aCx, &jsStateObj, rv);
-    if (NS_WARN_IF(rv.Failed())) {
-      return rv.StealNSResult();
-    }
-  } else {
-    MOZ_ASSERT(mState == eInitializedFromBase64);
-    MOZ_ASSERT(mData);
-
-    ErrorResult rv;
-    ReadFromBuffer(nullptr, aCx, mData, mSize, mVersion, &jsStateObj, rv);
-    if (NS_WARN_IF(rv.Failed())) {
-      return rv.StealNSResult();
-    }
+  ErrorResult rv;
+  Read(aCx, &jsStateObj, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
   }
 
   aValue.set(jsStateObj);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStructuredCloneContainer::DeserializeToVariant(JSContext* aCx,
                                                  nsIVariant** aData)
 {
   NS_ENSURE_ARG_POINTER(aData);
   *aData = nullptr;
 
-  if (mState == eNotInitialized) {
+  if (!DataLength()) {
     return NS_ERROR_FAILURE;
   }
 
   // Deserialize to a JS::Value.
   JS::Rooted<JS::Value> jsStateObj(aCx);
   nsresult rv = DeserializeToJsval(aCx, &jsStateObj);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -146,83 +125,52 @@ nsStructuredCloneContainer::DeserializeT
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut)
 {
   aOut.Truncate();
 
-  if (mState == eNotInitialized) {
+  if (!DataLength()) {
     return NS_ERROR_FAILURE;
   }
 
-  uint64_t* data;
-  size_t size;
-
-  if (mState == eInitializedFromJSVal) {
-    if (HasClonedDOMObjects()) {
-      return NS_ERROR_FAILURE;
-    }
-
-    data = BufferData();
-    size = BufferSize();
-  } else {
-    MOZ_ASSERT(mState == eInitializedFromBase64);
-    MOZ_ASSERT(mData);
-
-    data = mData;
-    size = mSize;
+  if (HasClonedDOMObjects()) {
+    return NS_ERROR_FAILURE;
   }
 
-  nsAutoCString binaryData(reinterpret_cast<char*>(data), size);
+  nsAutoCString binaryData(reinterpret_cast<char*>(Data()), DataLength());
   nsAutoCString base64Data;
   nsresult rv = Base64Encode(binaryData, base64Data);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   CopyASCIItoUTF16(base64Data, aOut);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStructuredCloneContainer::GetSerializedNBytes(uint64_t* aSize)
 {
   NS_ENSURE_ARG_POINTER(aSize);
 
-  if (mState == eNotInitialized) {
+  if (!DataLength()) {
     return NS_ERROR_FAILURE;
   }
 
-  if (mState == eInitializedFromJSVal) {
-    *aSize = BufferSize();
-    return NS_OK;
-  }
-
-  MOZ_ASSERT(mState == eInitializedFromBase64);
-
-  // mSize is a size_t, while aSize is a uint64_t.  We rely on an implicit cast
-  // here so that we'll get a compile error if a size_t-to-uint64_t cast is
-  // narrowing.
-  *aSize = mSize;
-
+  *aSize = DataLength();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStructuredCloneContainer::GetFormatVersion(uint32_t* aFormatVersion)
 {
   NS_ENSURE_ARG_POINTER(aFormatVersion);
 
-  if (mState == eNotInitialized) {
+  if (!DataLength()) {
     return NS_ERROR_FAILURE;
   }
 
-  if (mState == eInitializedFromJSVal) {
-    *aFormatVersion = JS_STRUCTURED_CLONE_VERSION;
-    return NS_OK;
-  }
-
-  MOZ_ASSERT(mState == eInitializedFromBase64);
   *aFormatVersion = mVersion;
   return NS_OK;
 }
--- a/dom/base/nsStructuredCloneContainer.h
+++ b/dom/base/nsStructuredCloneContainer.h
@@ -4,47 +4,37 @@
  * 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 nsStructuredCloneContainer_h__
 #define nsStructuredCloneContainer_h__
 
 #include "nsIStructuredCloneContainer.h"
 #include "mozilla/Attributes.h"
-#include "mozilla/dom/StructuredCloneHelper.h"
+#include "mozilla/dom/StructuredCloneIPCHelper.h"
 
 #define NS_STRUCTUREDCLONECONTAINER_CONTRACTID \
   "@mozilla.org/docshell/structured-clone-container;1"
 #define NS_STRUCTUREDCLONECONTAINER_CID \
 { /* 38bd0634-0fd4-46f0-b85f-13ced889eeec */       \
   0x38bd0634,                                      \
   0x0fd4,                                          \
   0x46f0,                                          \
   {0xb8, 0x5f, 0x13, 0xce, 0xd8, 0x89, 0xee, 0xec} \
 }
 
 class nsStructuredCloneContainer final
   : public nsIStructuredCloneContainer
-  , public mozilla::dom::StructuredCloneHelper
+  , public mozilla::dom::StructuredCloneIPCHelper
 {
   public:
     nsStructuredCloneContainer();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSISTRUCTUREDCLONECONTAINER
 
   private:
     ~nsStructuredCloneContainer();
 
-    enum {
-      eNotInitialized = 0,
-      eInitializedFromJSVal,
-      eInitializedFromBase64,
-    } mState;
-
-    uint64_t* mData;
-
-    // This needs to be size_t rather than a PR-type so it matches the JS API.
-    size_t mSize;
     uint32_t mVersion;
 };
 
 #endif
--- a/dom/broadcastchannel/BroadcastChannelChild.cpp
+++ b/dom/broadcastchannel/BroadcastChannelChild.cpp
@@ -6,17 +6,17 @@
 
 #include "BroadcastChannelChild.h"
 #include "BroadcastChannel.h"
 #include "jsapi.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
-#include "mozilla/dom/StructuredCloneHelper.h"
+#include "mozilla/dom/StructuredCloneIPCHelper.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "WorkerPrivate.h"
 
 namespace mozilla {
 
@@ -80,29 +80,27 @@ BroadcastChannelChild::RecvNotify(const 
     globalObject = workerPrivate->GlobalScope();
   }
 
   if (!globalObject || !jsapi.Init(globalObject)) {
     NS_WARNING("Failed to initialize AutoJSAPI object.");
     return true;
   }
 
-  JSContext* cx = jsapi.cx();
-  const SerializedStructuredCloneBuffer& buffer = aData.data();
-  StructuredCloneHelper cloneHelper(StructuredCloneHelper::CloningSupported,
-                                    StructuredCloneHelper::TransferringNotSupported,
-                                    StructuredCloneHelper::DifferentProcess);
-
+  StructuredCloneIPCHelper cloneHelper;
   cloneHelper.BlobImpls().AppendElements(blobs);
 
+  const SerializedStructuredCloneBuffer& buffer = aData.data();
+  cloneHelper.UseExternalData(buffer.data, buffer.dataLength);
+
+  JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> value(cx, JS::NullValue());
   if (buffer.dataLength) {
     ErrorResult rv;
-    cloneHelper.ReadFromBuffer(mBC->GetParentObject(), cx,
-                               buffer.data, buffer.dataLength, &value, rv);
+    cloneHelper.Read(cx, &value, rv);
     if (NS_WARN_IF(rv.Failed())) {
       return true;
     }
   }
 
   RootedDictionary<MessageEventInit> init(cx);
   init.mBubbles = false;
   init.mCancelable = false;
--- a/dom/ipc/StructuredCloneIPCHelper.cpp
+++ b/dom/ipc/StructuredCloneIPCHelper.cpp
@@ -25,26 +25,26 @@ namespace dom {
 
 bool
 StructuredCloneIPCHelper::Copy(const StructuredCloneIPCHelper& aHelper)
 {
   if (!aHelper.mData) {
     return true;
   }
 
-  uint64_t* data = static_cast<uint64_t*>(malloc(aHelper.mDataLength));
+  uint64_t* data = static_cast<uint64_t*>(js_malloc(aHelper.mDataLength));
   if (!data) {
     return false;
   }
 
   memcpy(data, aHelper.mData, aHelper.mDataLength);
 
   mData = data;
   mDataLength = aHelper.mDataLength;
-  mDataOwned = eAllocated;
+  mDataOwned = eJSAllocated;
 
   MOZ_ASSERT(BlobImpls().IsEmpty());
   BlobImpls().AppendElements(aHelper.BlobImpls());
 
   MOZ_ASSERT(GetImages().IsEmpty());
 
   return true;
 }
@@ -117,10 +117,28 @@ StructuredCloneIPCHelper::ReadIPCParams(
   }
 
   memcpy(data, mData, mDataLength);
   mData = data;
   mDataOwned = eJSAllocated;
   return true;
 }
 
+bool
+StructuredCloneIPCHelper::CopyExternalData(const void* aData,
+                                           size_t aDataLength)
+{
+  MOZ_ASSERT(!mData);
+  uint64_t* data = static_cast<uint64_t*>(js_malloc(aDataLength));
+  if (!data) {
+     return false;
+  }
+
+  memcpy(data, aData, aDataLength);
+  mData = data;
+  mDataLength = aDataLength;
+  mDataOwned = eJSAllocated;
+
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/StructuredCloneIPCHelper.h
+++ b/dom/ipc/StructuredCloneIPCHelper.h
@@ -11,35 +11,33 @@
 
 namespace IPC {
 class Message;
 }
 
 namespace mozilla {
 namespace dom {
 
-class StructuredCloneIPCHelper final : public StructuredCloneHelper
+class StructuredCloneIPCHelper : public StructuredCloneHelper
 {
 public:
   StructuredCloneIPCHelper()
     : StructuredCloneHelper(StructuredCloneHelper::CloningSupported,
                             StructuredCloneHelper::TransferringNotSupported,
                             StructuredCloneHelper::DifferentProcess)
     , mData(nullptr)
     , mDataLength(0)
     , mDataOwned(eNone)
   {}
 
   StructuredCloneIPCHelper(const StructuredCloneIPCHelper&) = delete;
 
   ~StructuredCloneIPCHelper()
   {
-    if (mDataOwned == eAllocated) {
-      free(mData);
-    } else if (mDataOwned == eJSAllocated) {
+    if (mDataOwned == eJSAllocated) {
       js_free(mData);
     }
   }
 
   StructuredCloneIPCHelper&
   operator=(const StructuredCloneIPCHelper& aOther) = delete;
 
   const nsTArray<nsRefPtr<BlobImpl>>& BlobImpls() const
@@ -65,16 +63,18 @@ public:
   void UseExternalData(uint64_t* aData, size_t aDataLength)
   {
     MOZ_ASSERT(!mData);
     mData = aData;
     mDataLength = aDataLength;
     MOZ_ASSERT(mDataOwned == eNone);
   }
 
+  bool CopyExternalData(const void* aData, size_t aDataLength);
+
   uint64_t* Data() const
   {
     return mData;
   }
 
   size_t DataLength() const
   {
     return mDataLength;
@@ -84,17 +84,16 @@ public:
   void WriteIPCParams(IPC::Message* aMessage) const;
   bool ReadIPCParams(const IPC::Message* aMessage, void** aIter);
 
 private:
   uint64_t* mData;
   size_t mDataLength;
   enum {
     eNone,
-    eAllocated,
-    eJSAllocated
+    eJSAllocated,
   } mDataOwned;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_StructuredCloneIPCHelper_h