Bug 961286 - Use move semantics for JSAutoStructuredCloneBuffer and wrappers. r=jorendorff, r=bent
authorKyle Huey <khuey@kylehuey.com>
Fri, 31 Jan 2014 21:50:07 -0500
changeset 166499 dffbfd00ac4e67e06211b57d877d7d05466b4e9f
parent 166498 aff0cc866eb85c0c254dcb09ce7912414f253d6a
child 166500 951fb38a568d2ca646b38dd25ad81cfea111d2d6
push id26128
push userphilringnalda@gmail.com
push dateSun, 02 Feb 2014 17:23:15 +0000
treeherdermozilla-central@5f88d54c28e0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff, bent
bugs961286
milestone29.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 961286 - Use move semantics for JSAutoStructuredCloneBuffer and wrappers. r=jorendorff, r=bent
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBCursor.h
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IndexedDatabase.h
dom/indexedDB/IndexedDatabaseInlines.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/XMLHttpRequest.cpp
dom/workers/XMLHttpRequest.h
js/public/StructuredClone.h
js/src/vm/StructuredClone.cpp
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -135,17 +135,17 @@ protected:
                  mCursor->mType == IDBCursor::OBJECTSTOREKEY ||
                  !mObjectKey.IsUnset());
 
       // Set new values.
       mCursor->mKey = mKey;
       mCursor->mObjectKey = mObjectKey;
       mCursor->mContinueToKey.Unset();
 
-      mCursor->mCloneReadInfo.Swap(mCloneReadInfo);
+      mCursor->mCloneReadInfo = Move(mCloneReadInfo);
       mCloneReadInfo.mCloneBuffer.clear();
     }
   }
 
   int32_t mCount;
   Key mKey;
   Key mObjectKey;
   StructuredCloneReadInfo mCloneReadInfo;
@@ -223,30 +223,30 @@ already_AddRefed<IDBCursor>
 IDBCursor::Create(IDBRequest* aRequest,
                   IDBTransaction* aTransaction,
                   IDBObjectStore* aObjectStore,
                   Direction aDirection,
                   const Key& aRangeKey,
                   const nsACString& aContinueQuery,
                   const nsACString& aContinueToQuery,
                   const Key& aKey,
-                  StructuredCloneReadInfo& aCloneReadInfo)
+                  StructuredCloneReadInfo&& aCloneReadInfo)
 {
   NS_ASSERTION(aObjectStore, "Null pointer!");
   NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::CreateCommon(aRequest, aTransaction, aObjectStore, aDirection,
                             aRangeKey, aContinueQuery, aContinueToQuery);
   NS_ASSERTION(cursor, "This shouldn't fail!");
 
   cursor->mObjectStore = aObjectStore;
   cursor->mType = OBJECTSTORE;
   cursor->mKey = aKey;
-  cursor->mCloneReadInfo.Swap(aCloneReadInfo);
+  cursor->mCloneReadInfo = Move(aCloneReadInfo);
 
   return cursor.forget();
 }
 
 // static
 already_AddRefed<IDBCursor>
 IDBCursor::Create(IDBRequest* aRequest,
                   IDBTransaction* aTransaction,
@@ -308,33 +308,33 @@ IDBCursor::Create(IDBRequest* aRequest,
                   IDBTransaction* aTransaction,
                   IDBIndex* aIndex,
                   Direction aDirection,
                   const Key& aRangeKey,
                   const nsACString& aContinueQuery,
                   const nsACString& aContinueToQuery,
                   const Key& aKey,
                   const Key& aObjectKey,
-                  StructuredCloneReadInfo& aCloneReadInfo)
+                  StructuredCloneReadInfo&& aCloneReadInfo)
 {
   NS_ASSERTION(aIndex, "Null pointer!");
   NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::CreateCommon(aRequest, aTransaction, aIndex->ObjectStore(),
                             aDirection, aRangeKey, aContinueQuery,
                             aContinueToQuery);
   NS_ASSERTION(cursor, "This shouldn't fail!");
 
   cursor->mObjectStore = aIndex->ObjectStore();
   cursor->mIndex = aIndex;
   cursor->mType = INDEXOBJECT;
   cursor->mKey = aKey;
   cursor->mObjectKey = aObjectKey;
-  cursor->mCloneReadInfo.Swap(aCloneReadInfo);
+  cursor->mCloneReadInfo = Move(aCloneReadInfo);
 
   return cursor.forget();
 }
 
 // static
 IDBCursor::Direction
 IDBCursor::ConvertDirection(mozilla::dom::IDBCursorDirection aDirection)
 {
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -77,17 +77,17 @@ public:
   Create(IDBRequest* aRequest,
          IDBTransaction* aTransaction,
          IDBObjectStore* aObjectStore,
          Direction aDirection,
          const Key& aRangeKey,
          const nsACString& aContinueQuery,
          const nsACString& aContinueToQuery,
          const Key& aKey,
-         StructuredCloneReadInfo& aCloneReadInfo);
+         StructuredCloneReadInfo&& aCloneReadInfo);
 
   // For OBJECTSTOREKEY cursors.
   static
   already_AddRefed<IDBCursor>
   Create(IDBRequest* aRequest,
          IDBTransaction* aTransaction,
          IDBObjectStore* aObjectStore,
          Direction aDirection,
@@ -116,17 +116,17 @@ public:
          IDBTransaction* aTransaction,
          IDBIndex* aIndex,
          Direction aDirection,
          const Key& aRangeKey,
          const nsACString& aContinueQuery,
          const nsACString& aContinueToQuery,
          const Key& aKey,
          const Key& aObjectKey,
-         StructuredCloneReadInfo& aCloneReadInfo);
+         StructuredCloneReadInfo&& aCloneReadInfo);
 
   IDBTransaction* Transaction() const
   {
     return mTransaction;
   }
 
   IDBRequest* Request() const
   {
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -31,16 +31,17 @@
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom;
 using namespace mozilla::dom::indexedDB::ipc;
 using mozilla::ErrorResult;
+using mozilla::Move;
 
 namespace {
 
 class IndexHelper : public AsyncConnectionHelper
 {
 public:
   IndexHelper(IDBTransaction* aTransaction,
               IDBRequest* aRequest,
@@ -773,17 +774,17 @@ IDBIndex::OpenCursorFromChildProcess(
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   cloneInfo.mFiles.SwapElements(aBlobs);
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
                       Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey,
-                      cloneInfo);
+                      Move(cloneInfo));
   IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!");
 
   cursor.forget(_retval);
   return NS_OK;
 }
 
@@ -2299,17 +2300,17 @@ OpenCursorHelper::EnsureCursor()
 
   NS_ASSERTION(mSerializedCloneReadInfo.data &&
                mSerializedCloneReadInfo.dataLength,
                "Shouldn't be possible!");
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(mRequest, mTransaction, mIndex, mDirection, mRangeKey,
                       mContinueQuery, mContinueToQuery, mKey, mObjectKey,
-                      mCloneReadInfo);
+                      Move(mCloneReadInfo));
   IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!");
 
   mCursor.swap(cursor);
   return NS_OK;
 }
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -54,16 +54,17 @@
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom;
 using namespace mozilla::dom::indexedDB::ipc;
 using mozilla::dom::quota::FileOutputStream;
 using mozilla::ErrorResult;
 using mozilla::fallible_t;
 using mozilla::LittleEndian;
+using mozilla::Move;
 using mozilla::NativeEndian;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 struct FileHandleData
 {
   nsString type;
   nsString name;
@@ -154,24 +155,25 @@ protected:
 };
 
 class AddHelper : public ObjectStoreHelper
 {
 public:
   AddHelper(IDBTransaction* aTransaction,
             IDBRequest* aRequest,
             IDBObjectStore* aObjectStore,
-            StructuredCloneWriteInfo& aCloneWriteInfo,
+            StructuredCloneWriteInfo&& aCloneWriteInfo,
             const Key& aKey,
             bool aOverwrite,
             nsTArray<IndexUpdateInfo>& aIndexUpdateInfo)
-  : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), mKey(aKey),
+  : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
+    mCloneWriteInfo(Move(aCloneWriteInfo)),
+    mKey(aKey),
     mOverwrite(aOverwrite)
   {
-    mCloneWriteInfo.Swap(aCloneWriteInfo);
     mIndexUpdateInfo.SwapElements(aIndexUpdateInfo);
   }
 
   ~AddHelper()
   {
     IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo);
   }
 
@@ -1936,17 +1938,17 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   if (!request) {
     IDB_WARNING("Failed to generate request!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
 
   nsRefPtr<AddHelper> helper =
-    new AddHelper(mTransaction, request, this, cloneWriteInfo, key,
+    new AddHelper(mTransaction, request, this, Move(cloneWriteInfo), key,
                   aOverwrite, updateInfo);
 
   nsresult rv = helper->DispatchToTransactionPool();
   if (NS_FAILED(rv)) {
     IDB_WARNING("Failed to dispatch!");
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return nullptr;
   }
@@ -2048,18 +2050,18 @@ IDBObjectStore::AddOrPutInternal(
     }
   }
 
   Key key(aKey);
 
   nsTArray<IndexUpdateInfo> updateInfo(aUpdateInfoArray);
 
   nsRefPtr<AddHelper> helper =
-    new AddHelper(mTransaction, request, this, cloneWriteInfo, key, aOverwrite,
-                  updateInfo);
+    new AddHelper(mTransaction, request, this, Move(cloneWriteInfo), key,
+                  aOverwrite, updateInfo);
 
   nsresult rv = helper->DispatchToTransactionPool();
   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
 #ifdef IDB_PROFILER_USE_MARKS
   if (aOverwrite) {
     IDB_PROFILER_MARK("IndexedDB Request %llu: "
                       "database(%s).transaction(%s).objectStore(%s).%s(%s)",
@@ -2398,17 +2400,17 @@ IDBObjectStore::OpenCursorFromChildProce
     IDB_WARNING("Failed to copy clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   cloneInfo.mFiles.SwapElements(aBlobs);
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(aRequest, mTransaction, this, direction, Key(),
-                      EmptyCString(), EmptyCString(), aKey, cloneInfo);
+                      EmptyCString(), EmptyCString(), aKey, Move(cloneInfo));
   IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!");
 
   cursor.forget(_retval);
   return NS_OK;
 }
 
@@ -3909,17 +3911,17 @@ OpenCursorHelper::EnsureCursor()
 
   NS_ASSERTION(mSerializedCloneReadInfo.data &&
                mSerializedCloneReadInfo.dataLength,
                "Shouldn't be possible!");
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection,
                       mRangeKey, mContinueQuery, mContinueToQuery, mKey,
-                      mCloneReadInfo);
+                      Move(mCloneReadInfo));
   IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!");
 
   mCursor.swap(cursor);
   return NS_OK;
 }
 
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -31,24 +31,16 @@
 class nsIDOMBlob;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class FileInfo;
 class IDBDatabase;
 class IDBTransaction;
 
-template <class T>
-void SwapData(T& aData1, T& aData2)
-{
-  T temp = aData2;
-  aData2 = aData1;
-  aData1 = temp;
-}
-
 struct StructuredCloneFile
 {
   bool operator==(const StructuredCloneFile& aOther) const
   {
     return this->mFile == aOther.mFile &&
            this->mFileInfo == aOther.mFileInfo &&
            this->mInputStream == aOther.mInputStream;
   }
@@ -60,22 +52,18 @@ struct StructuredCloneFile
 
 struct SerializedStructuredCloneReadInfo;
 
 struct StructuredCloneReadInfo
 {
   // In IndexedDatabaseInlines.h
   inline StructuredCloneReadInfo();
 
-  void Swap(StructuredCloneReadInfo& aCloneReadInfo)
-  {
-    mCloneBuffer.swap(aCloneReadInfo.mCloneBuffer);
-    mFiles.SwapElements(aCloneReadInfo.mFiles);
-    SwapData(mDatabase, aCloneReadInfo.mDatabase);
-  }
+  inline StructuredCloneReadInfo&
+  operator=(StructuredCloneReadInfo&& aCloneReadInfo);
 
   // In IndexedDatabaseInlines.h
   inline bool
   SetFromSerialized(const SerializedStructuredCloneReadInfo& aOther);
 
   JSAutoStructuredCloneBuffer mCloneBuffer;
   nsTArray<StructuredCloneFile> mFiles;
   IDBDatabase* mDatabase;
@@ -108,24 +96,17 @@ struct SerializedStructuredCloneReadInfo
 };
 
 struct SerializedStructuredCloneWriteInfo;
 
 struct StructuredCloneWriteInfo
 {
   // In IndexedDatabaseInlines.h
   inline StructuredCloneWriteInfo();
-
-  void Swap(StructuredCloneWriteInfo& aCloneWriteInfo)
-  {
-    mCloneBuffer.swap(aCloneWriteInfo.mCloneBuffer);
-    mFiles.SwapElements(aCloneWriteInfo.mFiles);
-    SwapData(mTransaction, aCloneWriteInfo.mTransaction);
-    SwapData(mOffsetToKeyProp, aCloneWriteInfo.mOffsetToKeyProp);
-  }
+  inline StructuredCloneWriteInfo(StructuredCloneWriteInfo&& aCloneWriteInfo);
 
   bool operator==(const StructuredCloneWriteInfo& aOther) const
   {
     return this->mCloneBuffer.nbytes() == aOther.mCloneBuffer.nbytes() &&
            this->mCloneBuffer.data() == aOther.mCloneBuffer.data() &&
            this->mFiles == aOther.mFiles &&
            this->mTransaction == aOther.mTransaction &&
            this->mOffsetToKeyProp == aOther.mOffsetToKeyProp;
--- a/dom/indexedDB/IndexedDatabaseInlines.h
+++ b/dom/indexedDB/IndexedDatabaseInlines.h
@@ -16,16 +16,28 @@ BEGIN_INDEXEDDB_NAMESPACE
 inline
 StructuredCloneWriteInfo::StructuredCloneWriteInfo()
 : mTransaction(nullptr),
   mOffsetToKeyProp(0)
 {
 }
 
 inline
+StructuredCloneWriteInfo::StructuredCloneWriteInfo(
+                                    StructuredCloneWriteInfo&& aCloneWriteInfo)
+: mCloneBuffer(Move(aCloneWriteInfo.mCloneBuffer))
+, mTransaction(aCloneWriteInfo.mTransaction)
+, mOffsetToKeyProp(aCloneWriteInfo.mOffsetToKeyProp)
+{
+  mFiles.SwapElements(aCloneWriteInfo.mFiles);
+  aCloneWriteInfo.mTransaction = nullptr;
+  aCloneWriteInfo.mOffsetToKeyProp = 0;
+}
+
+inline
 bool
 StructuredCloneWriteInfo::SetFromSerialized(
                                const SerializedStructuredCloneWriteInfo& aOther)
 {
   if (!aOther.dataLength) {
     mCloneBuffer.clear();
   }
   else if (!mCloneBuffer.copy(aOther.data, aOther.dataLength)) {
@@ -38,16 +50,29 @@ StructuredCloneWriteInfo::SetFromSeriali
 }
 
 inline
 StructuredCloneReadInfo::StructuredCloneReadInfo()
 : mDatabase(nullptr)
 {
 }
 
+inline StructuredCloneReadInfo&
+StructuredCloneReadInfo::operator=(StructuredCloneReadInfo&& aCloneReadInfo)
+{
+  MOZ_ASSERT(&aCloneReadInfo != this);
+
+  mCloneBuffer = Move(aCloneReadInfo.mCloneBuffer);
+  mFiles.Clear();
+  mFiles.SwapElements(aCloneReadInfo.mFiles);
+  mDatabase = aCloneReadInfo.mDatabase;
+  aCloneReadInfo.mDatabase = nullptr;
+  return *this;
+}
+
 inline
 bool
 StructuredCloneReadInfo::SetFromSerialized(
                                 const SerializedStructuredCloneReadInfo& aOther)
 {
   if (aOther.dataLength &&
       !mCloneBuffer.copy(aOther.data, aOther.dataLength)) {
     return false;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -954,23 +954,24 @@ class MessageEventRunnable MOZ_FINAL : p
   JSAutoStructuredCloneBuffer mBuffer;
   nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
   uint64_t mMessagePortSerial;
   bool mToMessagePort;
 
 public:
   MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
                        TargetAndBusyBehavior aBehavior,
-                       JSAutoStructuredCloneBuffer& aData,
+                       JSAutoStructuredCloneBuffer&& aData,
                        nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
                        bool aToMessagePort, uint64_t aMessagePortSerial)
-  : WorkerRunnable(aWorkerPrivate, aBehavior),
-    mMessagePortSerial(aMessagePortSerial), mToMessagePort(aToMessagePort)
+  : WorkerRunnable(aWorkerPrivate, aBehavior)
+  , mBuffer(Move(aData))
+  , mMessagePortSerial(aMessagePortSerial)
+  , mToMessagePort(aToMessagePort)
   {
-    mBuffer.swap(aData);
     mClonedObjects.SwapElements(aClonedObjects);
   }
 
   bool
   DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                    nsDOMEventTargetHelper* aTarget, bool aIsMainThread)
   {
     // Release reference to objects that were AddRef'd for
@@ -1021,17 +1022,17 @@ private:
       if (!aWorkerPrivate->IsAcceptingEvents()) {
         return true;
       }
 
       if (mToMessagePort) {
         return
           aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
                                                             mMessagePortSerial,
-                                                            mBuffer,
+                                                            Move(mBuffer),
                                                             mClonedObjects);
       }
 
       if (aWorkerPrivate->IsSuspended()) {
         aWorkerPrivate->QueueRunnable(this);
         return true;
       }
 
@@ -2783,17 +2784,17 @@ WorkerPrivateParent<Derived>::PostMessag
   if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) {
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
     return;
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(ParentAsWorkerPrivate(),
                              WorkerRunnable::WorkerThreadModifyBusyCount,
-                             buffer, clonedObjects, aToMessagePort,
+                             Move(buffer), clonedObjects, aToMessagePort,
                              aMessagePortSerial);
   if (!runnable->Dispatch(aCx)) {
     aRv.Throw(NS_ERROR_FAILURE);
   }
 }
 
 template <class Derived>
 void
@@ -2809,23 +2810,22 @@ WorkerPrivateParent<Derived>::PostMessag
   PostMessageInternal(aCx, aMessage, aTransferable, true, aMessagePortSerial,
                       aRv);
 }
 
 template <class Derived>
 bool
 WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
                                 JSContext* aCx, uint64_t aMessagePortSerial,
-                                JSAutoStructuredCloneBuffer& aBuffer,
+                                JSAutoStructuredCloneBuffer&& aBuffer,
                                 nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
 {
   AssertIsOnMainThread();
 
-  JSAutoStructuredCloneBuffer buffer;
-  buffer.swap(aBuffer);
+  JSAutoStructuredCloneBuffer buffer(Move(aBuffer));
 
   nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
   clonedObjects.SwapElements(aClonedObjects);
 
   SharedWorker* sharedWorker;
   if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
     // SharedWorker has already been unregistered?
     return true;
@@ -4988,17 +4988,17 @@ WorkerPrivate::PostMessageToParentIntern
   if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) {
     aRv = NS_ERROR_DOM_DATA_CLONE_ERR;
     return;
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(this,
                              WorkerRunnable::ParentThreadUnchangedBusyCount,
-                             buffer, clonedObjects, aToMessagePort,
+                             Move(buffer), clonedObjects, aToMessagePort,
                              aMessagePortSerial);
   if (!runnable->Dispatch(aCx)) {
     aRv = NS_ERROR_FAILURE;
   }
 }
 
 void
 WorkerPrivate::PostMessageToParentMessagePort(
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -372,17 +372,17 @@ public:
                            JS::Handle<JS::Value> aMessage,
                            const Optional<Sequence<JS::Value> >& aTransferable,
                            ErrorResult& aRv);
 
   bool
   DispatchMessageEventToMessagePort(
                                JSContext* aCx,
                                uint64_t aMessagePortSerial,
-                               JSAutoStructuredCloneBuffer& aBuffer,
+                               JSAutoStructuredCloneBuffer&& aBuffer,
                                nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects);
 
   uint64_t
   GetInnerWindowId();
 
   void
   UpdateJSContextOptions(JSContext* aCx, const JS::ContextOptions& aChromeOptions,
                          const JS::ContextOptions& aContentOptions);
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -787,24 +787,25 @@ class SendRunnable MOZ_FINAL : public Wo
   nsString mStringBody;
   JSAutoStructuredCloneBuffer mBody;
   nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
   bool mHasUploadListeners;
 
 public:
   SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
-               const nsAString& aStringBody, JSAutoStructuredCloneBuffer& aBody,
-               nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
+               const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody,
+               nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects,
                nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners)
-  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
-    mStringBody(aStringBody), mSyncLoopTarget(aSyncLoopTarget),
-    mHasUploadListeners(aHasUploadListeners)
+  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
+  , mStringBody(aStringBody)
+  , mBody(Move(aBody))
+  , mSyncLoopTarget(aSyncLoopTarget)
+  , mHasUploadListeners(aHasUploadListeners)
   {
-    mBody.swap(aBody);
     mClonedObjects.SwapElements(aClonedObjects);
   }
 
 private:
   ~SendRunnable()
   { }
 
   virtual nsresult
@@ -1263,18 +1264,17 @@ EventRunnable::WorkerRun(JSContext* aCx,
   }
   else {
     state->mResponseResult = mResponseResult;
 
     if (NS_SUCCEEDED(mResponseResult)) {
       if (mResponseBuffer.data()) {
         MOZ_ASSERT(JSVAL_IS_VOID(mResponse));
 
-        JSAutoStructuredCloneBuffer responseBuffer;
-        mResponseBuffer.swap(responseBuffer);
+        JSAutoStructuredCloneBuffer responseBuffer(Move(mResponseBuffer));
 
         JSStructuredCloneCallbacks* callbacks =
           aWorkerPrivate->IsChromeWorker() ?
           ChromeWorkerStructuredCloneCallbacks(false) :
           WorkerStructuredCloneCallbacks(false);
 
         nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
         clonedObjects.SwapElements(mClonedObjects);
@@ -1761,17 +1761,17 @@ XMLHttpRequest::Unpin()
 
   mRooted = false;
 
   NS_RELEASE_THIS();
 }
 
 void
 XMLHttpRequest::SendInternal(const nsAString& aStringBody,
-                             JSAutoStructuredCloneBuffer& aBody,
+                             JSAutoStructuredCloneBuffer&& aBody,
                              nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
                              ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   bool hasUploadListeners = mUpload ? mUpload->HasListeners() : false;
 
   MaybePin(aRv);
@@ -1789,17 +1789,17 @@ XMLHttpRequest::SendInternal(const nsASt
     syncLoopTarget = autoSyncLoop.ref().EventTarget();
   }
 
   mProxy->mOuterChannelId++;
 
   JSContext* cx = mWorkerPrivate->GetJSContext();
 
   nsRefPtr<SendRunnable> runnable =
-    new SendRunnable(mWorkerPrivate, mProxy, aStringBody, aBody,
+    new SendRunnable(mWorkerPrivate, mProxy, aStringBody, Move(aBody),
                      aClonedObjects, syncLoopTarget, hasUploadListeners);
   if (!runnable->Dispatch(cx)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   if (!isSyncXHR)  {
     autoUnpin.Clear();
@@ -2006,17 +2006,17 @@ XMLHttpRequest::Send(ErrorResult& aRv)
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   // Nothing to clone.
   JSAutoStructuredCloneBuffer buffer;
   nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
 
-  SendInternal(NullString(), buffer, clonedObjects, aRv);
+  SendInternal(NullString(), Move(buffer), clonedObjects, aRv);
 }
 
 void
 XMLHttpRequest::Send(const nsAString& aBody, ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   if (mCanceled) {
@@ -2028,17 +2028,17 @@ XMLHttpRequest::Send(const nsAString& aB
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   // Nothing to clone.
   JSAutoStructuredCloneBuffer buffer;
   nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
 
-  SendInternal(aBody, buffer, clonedObjects, aRv);
+  SendInternal(aBody, Move(buffer), clonedObjects, aRv);
 }
 
 void
 XMLHttpRequest::Send(JS::Handle<JSObject*> aBody, ErrorResult& aRv)
 {
   JSContext* cx = mWorkerPrivate->GetJSContext();
 
   MOZ_ASSERT(aBody);
@@ -2078,17 +2078,17 @@ XMLHttpRequest::Send(JS::Handle<JSObject
   nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
 
   JSAutoStructuredCloneBuffer buffer;
   if (!buffer.write(cx, valToClone, callbacks, &clonedObjects)) {
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
     return;
   }
 
-  SendInternal(EmptyString(), buffer, clonedObjects, aRv);
+  SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv);
 }
 
 void
 XMLHttpRequest::Send(const ArrayBuffer& aBody, ErrorResult& aRv)
 {
   JS::Rooted<JSObject*> obj(mWorkerPrivate->GetJSContext(), aBody.Obj());
   return Send(obj, aRv);
 }
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -280,16 +280,16 @@ private:
   bool
   SendInProgress() const
   {
     return mRooted;
   }
 
   void
   SendInternal(const nsAString& aStringBody,
-               JSAutoStructuredCloneBuffer& aBody,
+               JSAutoStructuredCloneBuffer&& aBody,
                nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
                ErrorResult& aRv);
 };
 
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_xmlhttprequest_h__
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -89,16 +89,19 @@ class JS_PUBLIC_API(JSAutoStructuredClon
     uint64_t *data_;
     size_t nbytes_;
     uint32_t version_;
 
   public:
     JSAutoStructuredCloneBuffer()
         : data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {}
 
+    JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer &&other);
+    JSAutoStructuredCloneBuffer &operator=(JSAutoStructuredCloneBuffer &&other);
+
     ~JSAutoStructuredCloneBuffer() { clear(); }
 
     uint64_t *data() const { return data_; }
     size_t nbytes() const { return nbytes_; }
 
     void clear();
 
     // Copy some memory. It will be automatically freed by the destructor.
@@ -118,19 +121,16 @@ class JS_PUBLIC_API(JSAutoStructuredClon
               const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr);
 
     bool write(JSContext *cx, JS::HandleValue v,
                const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr);
 
     bool write(JSContext *cx, JS::HandleValue v, JS::HandleValue transferable,
                const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr);
 
-    // Swap ownership with another JSAutoStructuredCloneBuffer.
-    void swap(JSAutoStructuredCloneBuffer &other);
-
   private:
     // Copy and assignment are not supported.
     JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer &other);
     JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other);
 };
 
 // The range of tag values the application may use for its own custom object types.
 #define JS_SCTAG_USER_MIN  ((uint32_t) 0xFFFF8000)
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1645,16 +1645,30 @@ JS_StructuredClone(JSContext *cx, JS::Ha
             if (!buf.write(cx, value, callbacks, closure))
                 return false;
         }
     }
 
     return buf.read(cx, vp, callbacks, closure);
 }
 
+JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer &&other)
+{
+    other.steal(&data_, &nbytes_, &version_);
+}
+
+JSAutoStructuredCloneBuffer&
+JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer &&other)
+{
+    JS_ASSERT(&other != this);
+    clear();
+    other.steal(&data_, &nbytes_, &version_);
+    return *this;
+}
+
 void
 JSAutoStructuredCloneBuffer::clear()
 {
     if (data_) {
         ClearStructuredClone(data_, nbytes_);
         data_ = nullptr;
         nbytes_ = 0;
         version_ = 0;
@@ -1738,32 +1752,16 @@ JSAutoStructuredCloneBuffer::write(JSCon
     if (!ok) {
         data_ = nullptr;
         nbytes_ = 0;
         version_ = JS_STRUCTURED_CLONE_VERSION;
     }
     return ok;
 }
 
-void
-JSAutoStructuredCloneBuffer::swap(JSAutoStructuredCloneBuffer &other)
-{
-    uint64_t *data = other.data_;
-    size_t nbytes = other.nbytes_;
-    uint32_t version = other.version_;
-
-    other.data_ = this->data_;
-    other.nbytes_ = this->nbytes_;
-    other.version_ = this->version_;
-
-    this->data_ = data;
-    this->nbytes_ = nbytes;
-    this->version_ = version;
-}
-
 JS_PUBLIC_API(void)
 JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
 {
     rt->structuredCloneCallbacks = callbacks;
 }
 
 JS_PUBLIC_API(bool)
 JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2)