Bug 1415980 - make hash keys movable and not copyable; r=erahm
☠☠ backed out by 69f43ac4d5a7 ☠ ☠
authorNathan Froyd <froydnj@mozilla.com>
Mon, 30 Jul 2018 17:15:11 -0400
changeset 429293 9035ff3757acd19ae5aece396bc2cc5ee61a58ce
parent 429292 6436144d9173d6a72128bd90b5e4efbe748b8204
child 429294 61f9854c9a74dfd01de72628050f99463b6f2cc4
push id34359
push usershindli@mozilla.com
push dateTue, 31 Jul 2018 09:53:19 +0000
treeherdermozilla-central@5a49a2ff0ee0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1415980
milestone63.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 1415980 - make hash keys movable and not copyable; r=erahm Everything that goes in a PLDHashtable (and its derivatives, like nsTHashtable) needs to inherit from PLDHashEntryHdr. But through a lack of enforcement, copy constructors for these derived classes didn't explicitly invoke the copy constructor for PLDHashEntryHdr (and the compiler didn't invoke the copy constructor for us). Instead, PLDHashTable explicitly copied around the bits that the copy constructor would have. The current setup has two problems: 1) Derived classes should be using move construction, not copy construction, since anything that's shuffling hash table keys/entries around will be using move construction. 2) Derived classes should take responsibility for transferring bits of superclass state around, and not rely on something else to handle that. The second point is not a huge problem for PLDHashTable (PLDHashTable only has to copy PLDHashEntryHdr's bits in a single place), but future hash table implementations that might move entries around more aggressively would have to insert compensation code all over the place. Additionally, if moving entries is implemented via memcpy (which is quite common), PLDHashTable copying around bits *again* is inefficient. Let's fix all these problems in one go, by: 1) Explicitly declaring the set of constructors that PLDHashEntryHdr implements (and does not implement). In particular, the copy constructor is deleted, so any derived classes that attempt to make themselves copyable will be detected at compile time: the compiler will complain that the superclass type is not copyable. This change on its own will result in many compiler errors, so... 2) Change any derived classes to implement move constructors instead of copy constructors. Note that some of these move constructors are, strictly speaking, unnecessary, since the relevant classes are moved via memcpy in nsTHashtable and its derivatives.
accessible/base/NotificationController.h
dom/animation/PseudoElementHashEntry.h
dom/base/nsDocument.cpp
dom/base/nsIdentifierMapEntry.h
dom/base/nsNodeInfoManager.h
dom/commandhandler/nsCommandParams.cpp
dom/commandhandler/nsCommandParams.h
dom/html/HTMLMediaElement.cpp
dom/smil/nsSMILCompositor.h
dom/storage/LocalStorageManager.h
dom/xslt/xslt/txExecutionState.h
gfx/thebes/gfxFontFeatures.h
gfx/thebes/gfxGlyphExtents.h
gfx/thebes/gfxUserFontSet.h
layout/painting/RetainedDisplayListHelpers.h
layout/style/Loader.h
modules/libpref/Preferences.cpp
netwerk/base/nsURIHashKey.h
netwerk/cache/nsCacheEntry.cpp
netwerk/cache/nsDiskCacheBinding.cpp
netwerk/cookie/nsCookieKey.h
netwerk/cookie/nsCookieService.cpp
parser/html/nsHtml5AtomTable.cpp
parser/html/nsHtml5AtomTable.h
security/manager/ssl/nsCertOverrideService.h
security/manager/ssl/nsClientAuthRemember.h
toolkit/components/places/History.h
toolkit/components/places/nsFaviconService.h
toolkit/components/places/nsNavHistory.h
toolkit/components/resistfingerprinting/nsRFPService.h
xpcom/ds/PLDHashTable.h
xpcom/ds/nsHashKeys.h
xpcom/ds/nsObserverList.h
xpcom/ds/nsPointerHashKeys.h
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -362,17 +362,20 @@ private:
   template<class T>
   class nsCOMPtrHashKey : public PLDHashEntryHdr
   {
   public:
     typedef T* KeyType;
     typedef const T* KeyTypePointer;
 
     explicit nsCOMPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
-    explicit nsCOMPtrHashKey(const nsPtrHashKey<T> &aToCopy) : mKey(aToCopy.mKey) {}
+    nsCOMPtrHashKey(nsCOMPtrHashKey<T>&& aOther)
+      : PLDHashEntryHdr(std::move(aOther))
+      , mKey(std::move(aOther.mKey))
+    {}
     ~nsCOMPtrHashKey() { }
 
     KeyType GetKey() const { return mKey; }
     bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
 
     static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
     static PLDHashNumber HashKey(KeyTypePointer aKey)
       { return NS_PTR_TO_INT32(aKey) >> 2; }
--- a/dom/animation/PseudoElementHashEntry.h
+++ b/dom/animation/PseudoElementHashEntry.h
@@ -19,17 +19,17 @@ class PseudoElementHashEntry : public PL
 {
 public:
   typedef NonOwningAnimationTarget KeyType;
   typedef const NonOwningAnimationTarget* KeyTypePointer;
 
   explicit PseudoElementHashEntry(KeyTypePointer aKey)
     : mElement(aKey->mElement)
     , mPseudoType(aKey->mPseudoType) { }
-  explicit PseudoElementHashEntry(const PseudoElementHashEntry& aCopy)=default;
+  PseudoElementHashEntry(PseudoElementHashEntry&& aOther) = default;
 
   ~PseudoElementHashEntry() = default;
 
   KeyType GetKey() const { return { mElement, mPseudoType }; }
   bool KeyEquals(KeyTypePointer aKey) const
   {
     return mElement == aKey->mElement &&
            mPseudoType == aKey->mPseudoType;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -381,17 +381,18 @@ nsIdentifierMapEntry::nsIdentifierMapEnt
 nsIdentifierMapEntry::nsIdentifierMapEntry(const nsIdentifierMapEntry::AtomOrString* aKey)
   : mKey(aKey ? *aKey : nullptr)
 {}
 
 nsIdentifierMapEntry::~nsIdentifierMapEntry()
 {}
 
 nsIdentifierMapEntry::nsIdentifierMapEntry(nsIdentifierMapEntry&& aOther)
-  : mKey(std::move(aOther.mKey))
+  : PLDHashEntryHdr(std::move(aOther))
+  , mKey(std::move(aOther.mKey))
   , mIdContentList(std::move(aOther.mIdContentList))
   , mNameContentList(std::move(aOther.mNameContentList))
   , mChangeCallbacks(std::move(aOther.mChangeCallbacks))
   , mImageElement(std::move(aOther.mImageElement))
 {}
 
 void
 nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback* aCallback)
--- a/dom/base/nsIdentifierMapEntry.h
+++ b/dom/base/nsIdentifierMapEntry.h
@@ -177,18 +177,19 @@ public:
   };
 
   struct ChangeCallbackEntry : public PLDHashEntryHdr {
     typedef const ChangeCallback KeyType;
     typedef const ChangeCallback* KeyTypePointer;
 
     explicit ChangeCallbackEntry(const ChangeCallback* aKey) :
       mKey(*aKey) { }
-    ChangeCallbackEntry(const ChangeCallbackEntry& toCopy) :
-      mKey(toCopy.mKey) { }
+    ChangeCallbackEntry(ChangeCallbackEntry&& aOther) :
+      PLDHashEntryHdr(std::move(aOther)),
+      mKey(std::move(aOther.mKey)) { }
 
     KeyType GetKey() const { return mKey; }
     bool KeyEquals(KeyTypePointer aKey) const {
       return aKey->mCallback == mKey.mCallback &&
              aKey->mData == mKey.mData &&
              aKey->mForImage == mKey.mForImage;
     }
 
--- a/dom/base/nsNodeInfoManager.h
+++ b/dom/base/nsNodeInfoManager.h
@@ -144,16 +144,17 @@ private:
   bool InternalSVGEnabled();
   bool InternalMathMLEnabled();
 
   class NodeInfoInnerKey :
     public nsPtrHashKey<mozilla::dom::NodeInfo::NodeInfoInner>
   {
   public:
     explicit NodeInfoInnerKey(KeyTypePointer aKey) : nsPtrHashKey(aKey) {}
+    NodeInfoInnerKey(NodeInfoInnerKey&&) = default;
     ~NodeInfoInnerKey() = default;
     bool KeyEquals(KeyTypePointer aKey) const { return *mKey == *aKey; }
     static PLDHashNumber HashKey(KeyTypePointer aKey) { return aKey->Hash(); }
   };
 
   nsDataHashtable<NodeInfoInnerKey, mozilla::dom::NodeInfo*> mNodeInfoHash;
   nsIDocument * MOZ_NON_OWNING_REF mDocument; // WEAK
   uint32_t mNonDocumentNodeInfos;
--- a/dom/commandhandler/nsCommandParams.cpp
+++ b/dom/commandhandler/nsCommandParams.cpp
@@ -331,20 +331,20 @@ nsCommandParams::HashMatchEntry(const PL
   return thisEntry->mEntryName.Equals(keyString);
 }
 
 void
 nsCommandParams::HashMoveEntry(PLDHashTable* aTable,
                                const PLDHashEntryHdr* aFrom,
                                PLDHashEntryHdr* aTo)
 {
-  const HashEntry* fromEntry = static_cast<const HashEntry*>(aFrom);
+  auto* fromEntry = const_cast<HashEntry*>(static_cast<const HashEntry*>(aFrom));
   HashEntry* toEntry = static_cast<HashEntry*>(aTo);
 
-  new (toEntry) HashEntry(*fromEntry);
+  new (KnownNotNull, toEntry) HashEntry(std::move(*fromEntry));
 
   fromEntry->~HashEntry();
 }
 
 void
 nsCommandParams::HashClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
 {
   HashEntry* thisEntry = static_cast<HashEntry*>(aEntry);
--- a/dom/commandhandler/nsCommandParams.h
+++ b/dom/commandhandler/nsCommandParams.h
@@ -81,17 +81,17 @@ protected:
     HashEntry(uint8_t aType, const char* aEntryName)
       : mEntryName(aEntryName)
       , mEntryType(aType)
       , mData()
     {
       Reset(mEntryType);
     }
 
-    HashEntry(const HashEntry& aRHS)
+    explicit HashEntry(const HashEntry& aRHS)
       : mEntryType(aRHS.mEntryType)
     {
       Reset(mEntryType);
       switch (mEntryType) {
         case eBooleanType:
           mData.mBoolean = aRHS.mData.mBoolean;
           break;
         case eLongType:
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3699,25 +3699,20 @@ HTMLMediaElement::MozCaptureStreamUntilE
   }
 
   return stream.forget();
 }
 
 class MediaElementSetForURI : public nsURIHashKey
 {
 public:
-  explicit MediaElementSetForURI(const nsIURI* aKey)
-    : nsURIHashKey(aKey)
-  {
-  }
-  MediaElementSetForURI(const MediaElementSetForURI& toCopy)
-    : nsURIHashKey(toCopy)
-    , mElements(toCopy.mElements)
-  {
-  }
+  explicit MediaElementSetForURI(const nsIURI* aKey) : nsURIHashKey(aKey) {}
+  MediaElementSetForURI(MediaElementSetForURI&& aOther)
+    : nsURIHashKey(std::move(aOther))
+    , mElements(std::move(aOther.mElements)) {}
   nsTArray<HTMLMediaElement*> mElements;
 };
 
 typedef nsTHashtable<MediaElementSetForURI> MediaElementURITable;
 // Elements in this table must have non-null mDecoder and mLoadingSrc, and those
 // can't change while the element is in the table. The table is keyed by
 // the element's mLoadingSrc. Each entry has a list of all elements with the
 // same mLoadingSrc.
--- a/dom/smil/nsSMILCompositor.h
+++ b/dom/smil/nsSMILCompositor.h
@@ -30,17 +30,18 @@ public:
   typedef const KeyType& KeyTypeRef;
   typedef const KeyType* KeyTypePointer;
 
   explicit nsSMILCompositor(KeyTypePointer aKey)
    : mKey(*aKey),
      mForceCompositing(false)
   { }
   nsSMILCompositor(nsSMILCompositor&& toMove)
-    : mKey(std::move(toMove.mKey)),
+    : PLDHashEntryHdr(std::move(toMove)),
+      mKey(std::move(toMove.mKey)),
       mAnimationFunctions(std::move(toMove.mAnimationFunctions)),
       mForceCompositing(false)
   { }
   ~nsSMILCompositor() { }
 
   // PLDHashEntryHdr methods
   KeyTypeRef GetKey() const { return mKey; }
   bool KeyEquals(KeyTypePointer aKey) const;
--- a/dom/storage/LocalStorageManager.h
+++ b/dom/storage/LocalStorageManager.h
@@ -61,18 +61,20 @@ private:
   class LocalStorageCacheHashKey : public nsCStringHashKey
   {
   public:
     explicit LocalStorageCacheHashKey(const nsACString* aKey)
       : nsCStringHashKey(aKey)
       , mCache(new LocalStorageCache(aKey))
     {}
 
-    LocalStorageCacheHashKey(const LocalStorageCacheHashKey& aOther)
-      : nsCStringHashKey(aOther)
+    LocalStorageCacheHashKey(LocalStorageCacheHashKey&& aOther)
+      : nsCStringHashKey(std::move(aOther))
+      , mCache(std::move(aOther.mCache))
+      , mCacheRef(std::move(aOther.mCacheRef))
     {
       NS_ERROR("Shouldn't be called");
     }
 
     LocalStorageCache* cache() { return mCache; }
     // Keep the cache referenced forever, used for sessionStorage.
     void HardRef() { mCacheRef = mCache; }
 
--- a/dom/xslt/xslt/txExecutionState.h
+++ b/dom/xslt/xslt/txExecutionState.h
@@ -24,18 +24,20 @@ class txInstruction;
 
 class txLoadedDocumentEntry : public nsStringHashKey
 {
 public:
     explicit txLoadedDocumentEntry(KeyTypePointer aStr) : nsStringHashKey(aStr),
                                                           mLoadResult(NS_OK)
     {
     }
-    txLoadedDocumentEntry(const txLoadedDocumentEntry& aToCopy)
-        : nsStringHashKey(aToCopy)
+    txLoadedDocumentEntry(txLoadedDocumentEntry&& aOther)
+        : nsStringHashKey(std::move(aOther))
+        , mDocument(std::move(aOther.mDocument))
+        , mLoadResult(std::move(aOther.mLoadResult))
     {
         NS_ERROR("We're horked.");
     }
     ~txLoadedDocumentEntry()
     {
         if (mDocument) {
             txXPathNodeUtils::release(mDocument);
         }
--- a/gfx/thebes/gfxFontFeatures.h
+++ b/gfx/thebes/gfxFontFeatures.h
@@ -107,17 +107,20 @@ private:
     };
 
     class FeatureValueHashEntry : public PLDHashEntryHdr {
     public:
         typedef const FeatureValueHashKey &KeyType;
         typedef const FeatureValueHashKey *KeyTypePointer;
 
         explicit FeatureValueHashEntry(KeyTypePointer aKey) { }
-        FeatureValueHashEntry(const FeatureValueHashEntry& toCopy)
+        FeatureValueHashEntry(FeatureValueHashEntry&& other)
+            : PLDHashEntryHdr(std::move(other))
+            , mKey(std::move(other.mKey))
+            , mValues(std::move(other.mValues))
         {
             NS_ERROR("Should not be called");
         }
         ~FeatureValueHashEntry() { }
 
         bool KeyEquals(const KeyTypePointer aKey) const;
         static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
         static PLDHashNumber HashKey(const KeyTypePointer aKey);
--- a/gfx/thebes/gfxGlyphExtents.h
+++ b/gfx/thebes/gfxGlyphExtents.h
@@ -84,19 +84,17 @@ public:
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
 private:
     class HashEntry : public nsUint32HashKey {
     public:
         // When constructing a new entry in the hashtable, we'll leave this
         // blank. The caller of Put() will fill this in.
         explicit HashEntry(KeyTypePointer aPtr) : nsUint32HashKey(aPtr) {}
-        HashEntry(const HashEntry& toCopy) : nsUint32HashKey(toCopy) {
-          x = toCopy.x; y = toCopy.y; width = toCopy.width; height = toCopy.height;
-        }
+        HashEntry(HashEntry&& other) = default;
 
         float x, y, width, height;
     };
 
     enum { BLOCK_SIZE_BITS = 7, BLOCK_SIZE = 1 << BLOCK_SIZE_BITS }; // 128-glyph blocks
 
     class GlyphWidths {
     public:
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -389,17 +389,18 @@ public:
             explicit Entry(KeyTypePointer aKey)
                 : mURI(aKey->mURI),
                   mPrincipal(aKey->mPrincipal),
                   mFontEntry(aKey->mFontEntry),
                   mPrivate(aKey->mPrivate)
             { }
 
             Entry(Entry&& aOther)
-                : mURI(std::move(aOther.mURI))
+                : PLDHashEntryHdr(std::move(aOther))
+                , mURI(std::move(aOther.mURI))
                 , mPrincipal(std::move(aOther.mPrincipal))
                 , mFontEntry(std::move(aOther.mFontEntry))
                 , mPrivate(std::move(aOther.mPrivate))
             { }
 
             ~Entry() { }
 
             bool KeyEquals(const KeyTypePointer aKey) const;
--- a/layout/painting/RetainedDisplayListHelpers.h
+++ b/layout/painting/RetainedDisplayListHelpers.h
@@ -23,17 +23,17 @@ struct DisplayItemKey
 class DisplayItemHashEntry : public PLDHashEntryHdr
 {
 public:
   typedef DisplayItemKey KeyType;
   typedef const DisplayItemKey* KeyTypePointer;
 
   explicit DisplayItemHashEntry(KeyTypePointer aKey)
     : mKey(*aKey) {}
-  explicit DisplayItemHashEntry(const DisplayItemHashEntry& aCopy)=default;
+  DisplayItemHashEntry(DisplayItemHashEntry&&) = default;
 
   ~DisplayItemHashEntry() = default;
 
   KeyType GetKey() const { return mKey; }
   bool KeyEquals(KeyTypePointer aKey) const
   {
     return mKey == *aKey;
   }
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -19,16 +19,17 @@
 #include "nsTObserverArray.h"
 #include "nsURIHashKey.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Move.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 class nsICSSLoaderObserver;
 class nsIConsoleReportCollector;
 class nsIContent;
 class nsIDocument;
@@ -64,21 +65,21 @@ public:
                                                ReferrerPolicy aReferrerPolicy)
     : nsURIHashKey(aURI),
       mPrincipal(aPrincipal),
       mCORSMode(aCORSMode),
       mReferrerPolicy(aReferrerPolicy)
   {
     MOZ_COUNT_CTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
   }
-  URIPrincipalReferrerPolicyAndCORSModeHashKey(const URIPrincipalReferrerPolicyAndCORSModeHashKey& toCopy)
-    : nsURIHashKey(toCopy),
-      mPrincipal(toCopy.mPrincipal),
-      mCORSMode(toCopy.mCORSMode),
-      mReferrerPolicy(toCopy.mReferrerPolicy)
+  URIPrincipalReferrerPolicyAndCORSModeHashKey(URIPrincipalReferrerPolicyAndCORSModeHashKey&& toMove)
+    : nsURIHashKey(std::move(toMove)),
+      mPrincipal(std::move(toMove.mPrincipal)),
+      mCORSMode(std::move(toMove.mCORSMode)),
+      mReferrerPolicy(std::move(toMove.mReferrerPolicy))
   {
     MOZ_COUNT_CTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
   }
   ~URIPrincipalReferrerPolicyAndCORSModeHashKey()
   {
     MOZ_COUNT_DTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
   }
 
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -2076,27 +2076,30 @@ public:
     , mWeakRef(do_GetWeakReference(aObserver))
     , mStrongRef(nullptr)
   {
     MOZ_COUNT_CTOR(PrefCallback);
     nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
     mCanonical = canonical;
   }
 
-  // Copy constructor needs to be explicit or the linker complains.
+  // This is explicitly not a copy constructor.
   explicit PrefCallback(const PrefCallback*& aCopy)
     : mDomain(aCopy->mDomain)
     , mBranch(aCopy->mBranch)
     , mWeakRef(aCopy->mWeakRef)
     , mStrongRef(aCopy->mStrongRef)
     , mCanonical(aCopy->mCanonical)
   {
     MOZ_COUNT_CTOR(PrefCallback);
   }
 
+  PrefCallback(const PrefCallback&) = delete;
+  PrefCallback(PrefCallback&&) = default;
+
   ~PrefCallback() { MOZ_COUNT_DTOR(PrefCallback); }
 
   bool KeyEquals(const PrefCallback* aKey) const
   {
     // We want to be able to look up a weakly-referencing PrefCallback after
     // its observer has died so we can remove it from the table. Once the
     // callback's observer dies, its canonical pointer is stale -- in
     // particular, we may have allocated a new observer in the same spot in
--- a/netwerk/base/nsURIHashKey.h
+++ b/netwerk/base/nsURIHashKey.h
@@ -4,31 +4,36 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsURIHashKey_h__
 #define nsURIHashKey_h__
 
 #include "PLDHashTable.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 #include "nsHashKeys.h"
+#include "mozilla/Move.h"
 #include "mozilla/Unused.h"
 
 /**
  * Hashtable key class to use with nsTHashtable/nsBaseHashtable
  */
 class nsURIHashKey : public PLDHashEntryHdr
 {
 public:
     typedef nsIURI* KeyType;
     typedef const nsIURI* KeyTypePointer;
 
     explicit nsURIHashKey(const nsIURI* aKey) :
         mKey(const_cast<nsIURI*>(aKey)) { MOZ_COUNT_CTOR(nsURIHashKey); }
-    nsURIHashKey(const nsURIHashKey& toCopy) :
-        mKey(toCopy.mKey) { MOZ_COUNT_CTOR(nsURIHashKey); }
+    nsURIHashKey(nsURIHashKey&& toMove)
+        : PLDHashEntryHdr(std::move(toMove))
+        , mKey(std::move(toMove.mKey))
+    {
+        MOZ_COUNT_CTOR(nsURIHashKey);
+    }
     ~nsURIHashKey() { MOZ_COUNT_DTOR(nsURIHashKey); }
 
     nsIURI* GetKey() const { return mKey; }
 
     bool KeyEquals(const nsIURI* aKey) const {
         bool eq;
         if (!mKey) {
             return !aKey;
--- a/netwerk/cache/nsCacheEntry.cpp
+++ b/netwerk/cache/nsCacheEntry.cpp
@@ -497,18 +497,18 @@ nsCacheEntryHashTable::MatchEntry(const 
 }
 
 
 void
 nsCacheEntryHashTable::MoveEntry(PLDHashTable * /* table */,
                                  const PLDHashEntryHdr *from,
                                  PLDHashEntryHdr       *to)
 {
-    ((nsCacheEntryHashTableEntry *)to)->cacheEntry =
-        ((nsCacheEntryHashTableEntry *)from)->cacheEntry;
+    new (KnownNotNull, to) nsCacheEntryHashTableEntry(std::move(*((nsCacheEntryHashTableEntry *)from)));
+    // No need to destroy `from`.
 }
 
 
 void
 nsCacheEntryHashTable::ClearEntry(PLDHashTable * /* table */,
                                   PLDHashEntryHdr * hashEntry)
 {
     ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry = nullptr;
--- a/netwerk/cache/nsDiskCacheBinding.cpp
+++ b/netwerk/cache/nsDiskCacheBinding.cpp
@@ -38,17 +38,18 @@ MatchEntry(const PLDHashEntryHdr *      
     return (hashEntry->mBinding->mRecord.HashNumber() == (PLDHashNumber) NS_PTR_TO_INT32(key));
 }
 
 static void
 MoveEntry(PLDHashTable *           /* table */,
           const PLDHashEntryHdr *     src,
           PLDHashEntryHdr       *     dst)
 {
-    ((HashTableEntry *)dst)->mBinding = ((HashTableEntry *)src)->mBinding;
+    new (KnownNotNull, dst) HashTableEntry(std::move(*(HashTableEntry*)src));
+    // No need to delete `src`.
 }
 
 
 static void
 ClearEntry(PLDHashTable *      /* table */,
            PLDHashEntryHdr *      header)
 {
     ((HashTableEntry *)header)->mBinding = nullptr;
--- a/netwerk/cookie/nsCookieKey.h
+++ b/netwerk/cookie/nsCookieKey.h
@@ -23,20 +23,18 @@ public:
     , mOriginAttributes(attrs)
   {}
 
   explicit nsCookieKey(KeyTypePointer other)
     : mBaseDomain(other->mBaseDomain)
     , mOriginAttributes(other->mOriginAttributes)
   {}
 
-  nsCookieKey(KeyType other)
-    : mBaseDomain(other.mBaseDomain)
-    , mOriginAttributes(other.mOriginAttributes)
-  {}
+  nsCookieKey(nsCookieKey&& other) = default;
+  nsCookieKey& operator=(nsCookieKey&&) = default;
 
   bool KeyEquals(KeyTypePointer other) const
   {
     return mBaseDomain == other->mBaseDomain &&
            mOriginAttributes == other->mOriginAttributes;
   }
 
   static KeyTypePointer KeyToPointer(KeyType aKey)
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -2893,17 +2893,17 @@ nsCookieService::Read()
     OriginAttributes attrs;
     stmt->GetUTF8String(IDX_ORIGIN_ATTRIBUTES, suffix);
     // If PopulateFromSuffix failed we just ignore the OA attributes
     // that we don't support
     Unused << attrs.PopulateFromSuffix(suffix);
 
     nsCookieKey key(baseDomain, attrs);
     CookieDomainTuple* tuple = mReadArray.AppendElement();
-    tuple->key = key;
+    tuple->key = std::move(key);
     tuple->cookie = GetCookieFromRow(stmt, attrs);
   }
 
   COOKIE_LOGSTRING(LogLevel::Debug, ("Read(): %zu cookies read", mReadArray.Length()));
 
   return RESULT_OK;
 }
 
--- a/parser/html/nsHtml5AtomTable.cpp
+++ b/parser/html/nsHtml5AtomTable.cpp
@@ -6,18 +6,18 @@
 #include "nsThreadUtils.h"
 
 nsHtml5AtomEntry::nsHtml5AtomEntry(KeyTypePointer aStr)
   : nsStringHashKey(aStr)
   , mAtom(nsDynamicAtom::Create(*aStr))
 {
 }
 
-nsHtml5AtomEntry::nsHtml5AtomEntry(const nsHtml5AtomEntry& aOther)
-  : nsStringHashKey(aOther)
+nsHtml5AtomEntry::nsHtml5AtomEntry(nsHtml5AtomEntry&& aOther)
+  : nsStringHashKey(std::move(aOther))
   , mAtom(nullptr)
 {
   MOZ_ASSERT_UNREACHABLE("nsHtml5AtomTable is broken; tried to copy an entry");
 }
 
 nsHtml5AtomEntry::~nsHtml5AtomEntry()
 {
   nsDynamicAtom::Destroy(mAtom);
--- a/parser/html/nsHtml5AtomTable.h
+++ b/parser/html/nsHtml5AtomTable.h
@@ -11,17 +11,17 @@
 #include "nsISerialEventTarget.h"
 
 #define RECENTLY_USED_PARSER_ATOMS_SIZE 31
 
 class nsHtml5AtomEntry : public nsStringHashKey
 {
 public:
   explicit nsHtml5AtomEntry(KeyTypePointer aStr);
-  nsHtml5AtomEntry(const nsHtml5AtomEntry& aOther);
+  nsHtml5AtomEntry(nsHtml5AtomEntry&& aOther);
   ~nsHtml5AtomEntry();
   inline nsAtom* GetAtom() { return mAtom; }
 
 private:
   nsDynamicAtom* mAtom;
 };
 
 /**
--- a/security/manager/ssl/nsCertOverrideService.h
+++ b/security/manager/ssl/nsCertOverrideService.h
@@ -76,17 +76,18 @@ class nsCertOverrideEntry final : public
     typedef const char* KeyTypePointer;
 
     // do nothing with aHost - we require mHead to be set before we're live!
     explicit nsCertOverrideEntry(KeyTypePointer aHostWithPortUTF8)
     {
     }
 
     nsCertOverrideEntry(nsCertOverrideEntry&& toMove)
-      : mSettings(std::move(toMove.mSettings))
+      : PLDHashEntryHdr(std::move(toMove))
+      , mSettings(std::move(toMove.mSettings))
       , mHostWithPort(std::move(toMove.mHostWithPort))
     {
     }
 
     ~nsCertOverrideEntry()
     {
     }
 
--- a/security/manager/ssl/nsClientAuthRemember.h
+++ b/security/manager/ssl/nsClientAuthRemember.h
@@ -60,17 +60,18 @@ class nsClientAuthRememberEntry final : 
     typedef const char* KeyTypePointer;
 
     // do nothing with aHost - we require mHead to be set before we're live!
     explicit nsClientAuthRememberEntry(KeyTypePointer aHostWithCertUTF8)
     {
     }
 
     nsClientAuthRememberEntry(nsClientAuthRememberEntry&& aToMove)
-      : mSettings(std::move(aToMove.mSettings))
+      : PLDHashEntryHdr(std::move(aToMove))
+      , mSettings(std::move(aToMove.mSettings))
       , mEntryKey(std::move(aToMove.mEntryKey))
     {
     }
 
     ~nsClientAuthRememberEntry()
     {
     }
 
--- a/toolkit/components/places/History.h
+++ b/toolkit/components/places/History.h
@@ -4,16 +4,17 @@
  * 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_places_History_h_
 #define mozilla_places_History_h_
 
 #include "mozilla/IHistory.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Move.h"
 #include "mozilla/Mutex.h"
 #include "mozIAsyncHistory.h"
 #include "nsIDownloadHistory.h"
 #include "Database.h"
 
 #include "mozilla/dom/Link.h"
 #include "mozilla/ipc/URIParams.h"
 #include "nsTHashtable.h"
@@ -207,18 +208,20 @@ private:
 
   class KeyClass : public nsURIHashKey
   {
   public:
     explicit KeyClass(const nsIURI* aURI)
     : nsURIHashKey(aURI)
     {
     }
-    KeyClass(const KeyClass& aOther)
-    : nsURIHashKey(aOther)
+    KeyClass(KeyClass&& aOther)
+      : nsURIHashKey(std::move(aOther))
+      , array(std::move(aOther.array))
+      , mVisited(std::move(aOther.mVisited))
     {
       MOZ_ASSERT_UNREACHABLE("Do not call me!");
     }
     size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     {
       return array.ShallowSizeOfExcludingThis(aMallocSizeOf);
     }
     ObserverArray array;
@@ -232,17 +235,17 @@ private:
    * history, to avoid saving these locations repeatedly in a short period.
    */
   class RecentURIKey : public nsURIHashKey
   {
   public:
     explicit RecentURIKey(const nsIURI* aURI) : nsURIHashKey(aURI)
     {
     }
-    RecentURIKey(const RecentURIKey& aOther) : nsURIHashKey(aOther)
+    RecentURIKey(RecentURIKey&& aOther) : nsURIHashKey(std::move(aOther))
     {
       MOZ_ASSERT_UNREACHABLE("Do not call me!");
     }
     MOZ_INIT_OUTSIDE_CTOR PRTime time;
   };
   nsTHashtable<RecentURIKey> mRecentlyVisitedURIs;
   /**
    * Whether aURI has been visited "recently".
--- a/toolkit/components/places/nsFaviconService.h
+++ b/toolkit/components/places/nsFaviconService.h
@@ -16,37 +16,40 @@
 #include "nsToolkitCompsCID.h"
 #include "nsURIHashKey.h"
 #include "nsINamed.h"
 #include "nsITimer.h"
 #include "Database.h"
 #include "imgITools.h"
 #include "mozilla/storage.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Move.h"
 
 #include "FaviconHelpers.h"
 
 // The target dimension in pixels for favicons we store, in reverse order.
 // When adding/removing sizes from here, make sure to update the vector size.
 static uint16_t sFaviconSizes[7] = {
   192, 144, 96, 64, 48, 32, 16
 };
 
 // forward class definitions
 class mozIStorageStatementCallback;
 
 class UnassociatedIconHashKey : public nsURIHashKey
 {
 public:
   explicit UnassociatedIconHashKey(const nsIURI* aURI)
-  : nsURIHashKey(aURI)
+    : nsURIHashKey(aURI)
   {
   }
-  UnassociatedIconHashKey(const UnassociatedIconHashKey& aOther)
-  : nsURIHashKey(aOther)
+  UnassociatedIconHashKey(UnassociatedIconHashKey&& aOther)
+    : nsURIHashKey(std::move(aOther))
+    , iconData(std::move(aOther.iconData))
+    , created(std::move(aOther.created))
   {
     MOZ_ASSERT_UNREACHABLE("Do not call me!");
   }
   mozilla::places::IconData iconData;
   PRTime created;
 };
 
 class nsFaviconService final : public nsIFaviconService
--- a/toolkit/components/places/nsNavHistory.h
+++ b/toolkit/components/places/nsNavHistory.h
@@ -527,18 +527,18 @@ protected:
   // Embed visits tracking.
   class VisitHashKey : public nsURIHashKey
   {
   public:
     explicit VisitHashKey(const nsIURI* aURI)
     : nsURIHashKey(aURI)
     {
     }
-    VisitHashKey(const VisitHashKey& aOther)
-    : nsURIHashKey(aOther)
+    VisitHashKey(VisitHashKey&& aOther)
+      : nsURIHashKey(std::move(aOther))
     {
       MOZ_ASSERT_UNREACHABLE("Do not call me!");
     }
     PRTime visitTime;
   };
 
   nsTHashtable<VisitHashKey> mEmbedVisits;
 
--- a/toolkit/components/resistfingerprinting/nsRFPService.h
+++ b/toolkit/components/resistfingerprinting/nsRFPService.h
@@ -103,21 +103,22 @@ public:
 
   explicit KeyboardHashKey(KeyTypePointer aOther)
     : mLang(aOther->mLang)
     , mRegion(aOther->mRegion)
     , mKeyIdx(aOther->mKeyIdx)
     , mKey(aOther->mKey)
   {}
 
-  KeyboardHashKey(KeyType aOther)
-    : mLang(aOther.mLang)
-    , mRegion(aOther.mRegion)
-    , mKeyIdx(aOther.mKeyIdx)
-    , mKey(aOther.mKey)
+  KeyboardHashKey(KeyboardHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mLang(std::move(aOther.mLang))
+    , mRegion(std::move(aOther.mRegion))
+    , mKeyIdx(std::move(aOther.mKeyIdx))
+    , mKey(std::move(aOther.mKey))
   {}
 
   ~KeyboardHashKey()
   {}
 
   bool KeyEquals(KeyTypePointer aOther) const
   {
     return mLang == aOther->mLang &&
--- a/xpcom/ds/PLDHashTable.h
+++ b/xpcom/ds/PLDHashTable.h
@@ -33,16 +33,23 @@ struct PLDHashTableOps;
 // Each hash table sub-type should make its entry type a subclass of
 // PLDHashEntryHdr. The mKeyHash member contains the result of multiplying the
 // hash code returned from the hashKey callback (see below) by kGoldenRatio,
 // then constraining the result to avoid the magic 0 and 1 values. The stored
 // mKeyHash value is table size invariant, and it is maintained automatically
 // -- users need never access it.
 struct PLDHashEntryHdr
 {
+  PLDHashEntryHdr() = default;
+  PLDHashEntryHdr(const PLDHashEntryHdr&) = delete;
+  PLDHashEntryHdr(const PLDHashEntryHdr&&) = delete;
+  PLDHashEntryHdr& operator=(const PLDHashEntryHdr&) = delete;
+  PLDHashEntryHdr(PLDHashEntryHdr&&) = default;
+  PLDHashEntryHdr& operator=(PLDHashEntryHdr&&) = default;
+
 private:
   friend class PLDHashTable;
 
   PLDHashNumber mKeyHash;
 };
 
 #ifdef DEBUG
 
--- a/xpcom/ds/nsHashKeys.h
+++ b/xpcom/ds/nsHashKeys.h
@@ -19,18 +19,19 @@
 #include "nsCRTGlue.h"
 #include "nsUnicharUtils.h"
 #include "nsPointerHashKeys.h"
 
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <utility>
+
 #include "mozilla/HashFunctions.h"
-#include "mozilla/Move.h"
 
 namespace mozilla {
 
 // These are defined analogously to the HashString overloads in mfbt.
 
 inline uint32_t
 HashString(const nsAString& aStr)
 {
@@ -76,17 +77,21 @@ HashString(const nsACString& aStr)
  */
 class nsStringHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const nsAString& KeyType;
   typedef const nsAString* KeyTypePointer;
 
   explicit nsStringHashKey(KeyTypePointer aStr) : mStr(*aStr) {}
-  nsStringHashKey(const nsStringHashKey& aToCopy) : mStr(aToCopy.mStr) {}
+  nsStringHashKey(const nsStringHashKey&) = delete;
+  nsStringHashKey(nsStringHashKey&& aToMove)
+    : PLDHashEntryHdr(std::move(aToMove))
+    , mStr(std::move(aToMove.mStr))
+  {}
   ~nsStringHashKey() {}
 
   KeyType GetKey() const { return mStr; }
   bool KeyEquals(const KeyTypePointer aKey) const
   {
     return mStr.Equals(*aKey);
   }
 
@@ -102,17 +107,17 @@ public:
   {
     return GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   }
 #endif
 
   enum { ALLOW_MEMMOVE = true };
 
 private:
-  const nsString mStr;
+  nsString mStr;
 };
 
 #ifdef MOZILLA_INTERNAL_API
 
 /**
  * hashkey wrapper using nsAString KeyType
  *
  * This is internal-API only because nsCaseInsensitiveStringComparator is
@@ -126,18 +131,21 @@ public:
   typedef const nsAString& KeyType;
   typedef const nsAString* KeyTypePointer;
 
   explicit nsStringCaseInsensitiveHashKey(KeyTypePointer aStr)
     : mStr(*aStr)
   {
     // take it easy just deal HashKey
   }
-  nsStringCaseInsensitiveHashKey(const nsStringCaseInsensitiveHashKey& aToCopy)
-    : mStr(aToCopy.mStr)
+
+  nsStringCaseInsensitiveHashKey(const nsStringCaseInsensitiveHashKey&) = delete;
+  nsStringCaseInsensitiveHashKey(nsStringCaseInsensitiveHashKey&& aToMove)
+    : PLDHashEntryHdr(std::move(aToMove))
+    , mStr(std::move(aToMove.mStr))
   {
   }
   ~nsStringCaseInsensitiveHashKey() {}
 
   KeyType GetKey() const { return mStr; }
   bool KeyEquals(const KeyTypePointer aKey) const
   {
     return mStr.Equals(*aKey, nsCaseInsensitiveStringComparator());
@@ -171,17 +179,20 @@ private:
  */
 class nsCStringHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const nsACString& KeyType;
   typedef const nsACString* KeyTypePointer;
 
   explicit nsCStringHashKey(const nsACString* aStr) : mStr(*aStr) {}
-  nsCStringHashKey(const nsCStringHashKey& aToCopy) : mStr(aToCopy.mStr) {}
+  nsCStringHashKey(nsCStringHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mStr(std::move(aOther.mStr))
+  {}
   ~nsCStringHashKey() {}
 
   KeyType GetKey() const { return mStr; }
   bool KeyEquals(KeyTypePointer aKey) const { return mStr.Equals(*aKey); }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey)
   {
@@ -209,17 +220,20 @@ private:
  */
 class nsUint32HashKey : public PLDHashEntryHdr
 {
 public:
   typedef const uint32_t& KeyType;
   typedef const uint32_t* KeyTypePointer;
 
   explicit nsUint32HashKey(KeyTypePointer aKey) : mValue(*aKey) {}
-  nsUint32HashKey(const nsUint32HashKey& aToCopy) : mValue(aToCopy.mValue) {}
+  nsUint32HashKey(nsUint32HashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mValue(std::move(aOther.mValue))
+  {}
   ~nsUint32HashKey() {}
 
   KeyType GetKey() const { return mValue; }
   bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey) { return *aKey; }
   enum { ALLOW_MEMMOVE = true };
@@ -235,17 +249,20 @@ private:
  */
 class nsUint64HashKey : public PLDHashEntryHdr
 {
 public:
   typedef const uint64_t& KeyType;
   typedef const uint64_t* KeyTypePointer;
 
   explicit nsUint64HashKey(KeyTypePointer aKey) : mValue(*aKey) {}
-  nsUint64HashKey(const nsUint64HashKey& aToCopy) : mValue(aToCopy.mValue) {}
+  nsUint64HashKey(nsUint64HashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mValue(std::move(aOther.mValue))
+  {}
   ~nsUint64HashKey() {}
 
   KeyType GetKey() const { return mValue; }
   bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey)
   {
@@ -264,17 +281,20 @@ private:
  */
 class nsFloatHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const float& KeyType;
   typedef const float* KeyTypePointer;
 
   explicit nsFloatHashKey(KeyTypePointer aKey) : mValue(*aKey) {}
-  nsFloatHashKey(const nsFloatHashKey& aToCopy) : mValue(aToCopy.mValue) {}
+  nsFloatHashKey(nsFloatHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mValue(std::move(aOther.mValue))
+  {}
   ~nsFloatHashKey() {}
 
   KeyType GetKey() const { return mValue; }
   bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey)
   {
@@ -293,17 +313,19 @@ private:
  */
 class IntPtrHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const intptr_t& KeyType;
   typedef const intptr_t* KeyTypePointer;
 
   explicit IntPtrHashKey(KeyTypePointer aKey) : mValue(*aKey) {}
-  IntPtrHashKey(const IntPtrHashKey& aToCopy) : mValue(aToCopy.mValue) {}
+  IntPtrHashKey(IntPtrHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mValue(aOther.mValue) {}
   ~IntPtrHashKey() {}
 
   KeyType GetKey() const { return mValue; }
   bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey)
   {
@@ -325,18 +347,19 @@ class nsISupportsHashKey : public PLDHas
 public:
   typedef nsISupports* KeyType;
   typedef const nsISupports* KeyTypePointer;
 
   explicit nsISupportsHashKey(const nsISupports* aKey)
     : mSupports(const_cast<nsISupports*>(aKey))
   {
   }
-  nsISupportsHashKey(const nsISupportsHashKey& aToCopy)
-    : mSupports(aToCopy.mSupports)
+  nsISupportsHashKey(nsISupportsHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mSupports(std::move(aOther.mSupports))
   {
   }
   ~nsISupportsHashKey() {}
 
   KeyType GetKey() const { return mSupports; }
   bool KeyEquals(KeyTypePointer aKey) const { return aKey == mSupports; }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
@@ -358,17 +381,20 @@ private:
 template<class T>
 class nsRefPtrHashKey : public PLDHashEntryHdr
 {
 public:
   typedef T* KeyType;
   typedef const T* KeyTypePointer;
 
   explicit nsRefPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
-  nsRefPtrHashKey(const nsRefPtrHashKey& aToCopy) : mKey(aToCopy.mKey) {}
+  nsRefPtrHashKey(nsRefPtrHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mKey(std::move(aOther.mKey))
+  {}
   ~nsRefPtrHashKey() {}
 
   KeyType GetKey() const { return mKey; }
   bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey)
   {
@@ -398,18 +424,18 @@ ImplCycleCollectionTraverse(nsCycleColle
  * @see nsTHashtable::EntryType for specification
  */
 
 template<class T>
 class nsClearingPtrHashKey : public nsPtrHashKey<T>
 {
 public:
   explicit nsClearingPtrHashKey(const T* aKey) : nsPtrHashKey<T>(aKey) {}
-  nsClearingPtrHashKey(const nsClearingPtrHashKey<T>& aToCopy)
-    : nsPtrHashKey<T>(aToCopy)
+  nsClearingPtrHashKey(nsClearingPtrHashKey&& aToMove)
+    : nsPtrHashKey<T>(std::move(aToMove))
   {
   }
   ~nsClearingPtrHashKey() { nsPtrHashKey<T>::mKey = nullptr; }
 };
 
 typedef nsClearingPtrHashKey<const void> nsClearingVoidPtrHashKey;
 
 /**
@@ -449,48 +475,53 @@ protected:
  */
 class nsIDHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const nsID& KeyType;
   typedef const nsID* KeyTypePointer;
 
   explicit nsIDHashKey(const nsID* aInID) : mID(*aInID) {}
-  nsIDHashKey(const nsIDHashKey& aToCopy) : mID(aToCopy.mID) {}
+  nsIDHashKey(nsIDHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mID(std::move(aOther.mID))
+  {}
   ~nsIDHashKey() {}
 
   KeyType GetKey() const { return mID; }
   bool KeyEquals(KeyTypePointer aKey) const { return aKey->Equals(mID); }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey)
   {
     // Hash the nsID object's raw bytes.
     return mozilla::HashBytes(aKey, sizeof(KeyType));
   }
 
   enum { ALLOW_MEMMOVE = true };
 
 private:
-  const nsID mID;
+  nsID mID;
 };
 
 /**
  * hashkey wrapper using nsID* KeyType
  *
  * @see nsTHashtable::EntryType for specification
  */
 class nsIDPointerHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const nsID* KeyType;
   typedef const nsID* KeyTypePointer;
 
   explicit nsIDPointerHashKey(const nsID* aInID) : mID(aInID) {}
-  nsIDPointerHashKey(const nsIDPointerHashKey& aToCopy) : mID(aToCopy.mID) {}
+  nsIDPointerHashKey(nsIDPointerHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mID(aOther.mID) {}
   ~nsIDPointerHashKey() = default;
 
   KeyType GetKey() const { return mID; }
   bool KeyEquals(KeyTypePointer aKey) const { return aKey->Equals(*mID); }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey)
   {
@@ -516,17 +547,20 @@ private:
  */
 class nsDepCharHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const char* KeyType;
   typedef const char* KeyTypePointer;
 
   explicit nsDepCharHashKey(const char* aKey) : mKey(aKey) {}
-  nsDepCharHashKey(const nsDepCharHashKey& aToCopy) : mKey(aToCopy.mKey) {}
+  nsDepCharHashKey(nsDepCharHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mKey(std::move(aOther.mKey))
+  {}
   ~nsDepCharHashKey() {}
 
   const char* GetKey() const { return mKey; }
   bool KeyEquals(const char* aKey) const { return !strcmp(mKey, aKey); }
 
   static const char* KeyToPointer(const char* aKey) { return aKey; }
   static PLDHashNumber HashKey(const char* aKey)
   {
@@ -545,21 +579,18 @@ private:
  */
 class nsCharPtrHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const char* KeyType;
   typedef const char* KeyTypePointer;
 
   explicit nsCharPtrHashKey(const char* aKey) : mKey(strdup(aKey)) {}
-  nsCharPtrHashKey(const nsCharPtrHashKey& aToCopy)
-    : mKey(strdup(aToCopy.mKey))
-  {
-  }
 
+  nsCharPtrHashKey(const nsCharPtrHashKey&) = delete;
   nsCharPtrHashKey(nsCharPtrHashKey&& aOther)
     : mKey(aOther.mKey)
   {
     aOther.mKey = nullptr;
   }
 
   ~nsCharPtrHashKey()
   {
@@ -595,21 +626,18 @@ private:
  */
 class nsUnicharPtrHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const char16_t* KeyType;
   typedef const char16_t* KeyTypePointer;
 
   explicit nsUnicharPtrHashKey(const char16_t* aKey) : mKey(NS_strdup(aKey)) {}
-  nsUnicharPtrHashKey(const nsUnicharPtrHashKey& aToCopy)
-    : mKey(NS_strdup(aToCopy.mKey))
-  {
-  }
 
+  nsUnicharPtrHashKey(const nsUnicharPtrHashKey& aToCopy) = delete;
   nsUnicharPtrHashKey(nsUnicharPtrHashKey&& aOther)
     : mKey(aOther.mKey)
   {
     aOther.mKey = nullptr;
   }
 
   ~nsUnicharPtrHashKey()
   {
@@ -646,17 +674,20 @@ class nsHashableHashKey : public PLDHash
 public:
   typedef nsIHashable* KeyType;
   typedef const nsIHashable* KeyTypePointer;
 
   explicit nsHashableHashKey(const nsIHashable* aKey)
     : mKey(const_cast<nsIHashable*>(aKey))
   {
   }
-  nsHashableHashKey(const nsHashableHashKey& aToCopy) : mKey(aToCopy.mKey) {}
+  nsHashableHashKey(nsHashableHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mKey(std::move(aOther.mKey))
+  {}
   ~nsHashableHashKey() {}
 
   nsIHashable* GetKey() const { return mKey; }
 
   bool KeyEquals(const nsIHashable* aKey) const
   {
     bool eq;
     if (NS_SUCCEEDED(mKey->Equals(const_cast<nsIHashable*>(aKey), &eq))) {
@@ -701,17 +732,20 @@ Hash(const T& aValue)
 template<typename T>
 class nsGenericHashKey : public PLDHashEntryHdr
 {
 public:
   typedef const T& KeyType;
   typedef const T* KeyTypePointer;
 
   explicit nsGenericHashKey(KeyTypePointer aKey) : mKey(*aKey) {}
-  nsGenericHashKey(const nsGenericHashKey<T>& aOther) : mKey(aOther.mKey) {}
+  nsGenericHashKey(const nsGenericHashKey&) = delete;
+  nsGenericHashKey(nsGenericHashKey&& aOther)
+    : PLDHashEntryHdr(std::move(aOther))
+    , mKey(std::move(aOther.mKey)) {}
 
   KeyType GetKey() const { return mKey; }
   bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mKey; }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey) { return ::mozilla::Hash(*aKey); }
   enum { ALLOW_MEMMOVE = true };
 
--- a/xpcom/ds/nsObserverList.h
+++ b/xpcom/ds/nsObserverList.h
@@ -46,16 +46,22 @@ class nsObserverList : public nsCharPtrH
   friend class nsObserverService;
 
 public:
   explicit nsObserverList(const char* aKey) : nsCharPtrHashKey(aKey)
   {
     MOZ_COUNT_CTOR(nsObserverList);
   }
 
+  nsObserverList(nsObserverList&& aOther)
+    : nsCharPtrHashKey(std::move(aOther))
+    , mObservers(std::move(aOther.mObservers))
+  {
+  }
+
   ~nsObserverList()
   {
     MOZ_COUNT_DTOR(nsObserverList);
   }
 
   MOZ_MUST_USE nsresult AddObserver(nsIObserver* aObserver, bool aOwnsWeak);
   MOZ_MUST_USE nsresult RemoveObserver(nsIObserver* aObserver);
 
--- a/xpcom/ds/nsPointerHashKeys.h
+++ b/xpcom/ds/nsPointerHashKeys.h
@@ -22,17 +22,20 @@
 template<class T>
 class nsPtrHashKey : public PLDHashEntryHdr
 {
 public:
   typedef T* KeyType;
   typedef const T* KeyTypePointer;
 
   explicit nsPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
-  nsPtrHashKey(const nsPtrHashKey<T>& aToCopy) : mKey(aToCopy.mKey) {}
+  nsPtrHashKey(nsPtrHashKey<T>&& aToMove)
+    : PLDHashEntryHdr(std::move(aToMove))
+    , mKey(std::move(aToMove.mKey))
+  {}
   ~nsPtrHashKey() {}
 
   KeyType GetKey() const { return mKey; }
   bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
 
   static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey)
   {