Bug 749981: Remove Node.getUserData / setUserData. r=smaug
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 17 Mar 2018 05:30:49 +0100
changeset 408692 a6528c5018d22c41a03fe1353e188ea0f8526d93
parent 408691 384c57a10906f919aa27af99575186e9f14aaa20
child 408693 2e74592c8f953de873f5495d2fa9afa9661ac99c
push id101009
push userecoal95@gmail.com
push dateSat, 17 Mar 2018 18:38:53 +0000
treeherdermozilla-inbound@a6528c5018d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs749981
milestone61.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 749981: Remove Node.getUserData / setUserData. r=smaug Summary: MozReview-Commit-ID: JkUCvVZ4V2Y Reviewers: smaug Bug #: 749981 Differential Revision: https://phabricator.services.mozilla.com/D749 MozReview-Commit-ID: KadWzpMjdW
dom/base/FragmentOrElement.cpp
dom/base/nsCCUncollectableMarker.cpp
dom/base/nsDeprecatedOperationList.h
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/base/nsINode.cpp
dom/base/nsINode.h
dom/base/nsNodeUtils.cpp
dom/base/nsNodeUtils.h
dom/base/nsPropertyTable.cpp
dom/base/nsPropertyTable.h
dom/base/test/mochitest.ini
dom/base/test/test_bug548463.html
dom/base/test/test_xbl_userdata.xhtml
dom/webidl/Node.webidl
js/xpconnect/crashtests/462926.html
js/xpconnect/crashtests/crashtests.list
js/xpconnect/tests/chrome/test_weakmaps.xul
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1537,23 +1537,16 @@ FragmentOrElement::MarkNodeChildren(nsIN
   if (o) {
     JS::ExposeObjectToActiveJS(o);
   }
 
   EventListenerManager* elm = aNode->GetExistingListenerManager();
   if (elm) {
     elm->MarkForCC();
   }
-
-  if (aNode->HasProperties()) {
-    nsIDocument* ownerDoc = aNode->OwnerDoc();
-    ownerDoc->PropertyTable(DOM_USER_DATA)->
-      Enumerate(aNode, FragmentOrElement::MarkUserData,
-                &nsCCUncollectableMarker::sGeneration);
-  }
 }
 
 nsINode*
 FindOptimizableSubtreeRoot(nsINode* aNode)
 {
   nsINode* p;
   while ((p = aNode->GetParentNode())) {
     if (aNode->UnoptimizableCCNode()) {
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -81,25 +81,16 @@ nsCCUncollectableMarker::Init()
   NS_ENSURE_SUCCESS(rv, rv);
 
   sInited = true;
 
   return NS_OK;
 }
 
 static void
-MarkUserData(void* aNode, nsAtom* aKey, void* aValue, void* aData)
-{
-  nsIDocument* d = static_cast<nsINode*>(aNode)->GetUncomposedDoc();
-  if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
-    Element::MarkUserData(aNode, aKey, aValue, aData);
-  }
-}
-
-static void
 MarkChildMessageManagers(nsIMessageBroadcaster* aMM)
 {
   aMM->MarkForCC();
 
   uint32_t tabChildCount = 0;
   aMM->GetChildCount(&tabChildCount);
   for (uint32_t j = 0; j < tabChildCount; ++j) {
     nsCOMPtr<nsIMessageListenerManager> childMM;
@@ -185,18 +176,17 @@ MarkMessageManagers()
     }
   }
   if (nsFrameMessageManager::sSameProcessParentManager) {
     nsFrameMessageManager::sSameProcessParentManager->MarkForCC();
   }
 }
 
 void
-MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS,
-                  bool aPrepareForCC)
+MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS)
 {
   if (!aViewer) {
     return;
   }
 
   nsIDocument *doc = aViewer->GetDocument();
   if (doc &&
       doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
@@ -210,111 +200,104 @@ MarkContentViewer(nsIContentViewer* aVie
       if (win) {
         elm = win->GetExistingListenerManager();
         if (elm) {
           elm->MarkForCC();
         }
         static_cast<nsGlobalWindowInner*>(win.get())->AsInner()->
           TimeoutManager().UnmarkGrayTimers();
       }
-    } else if (aPrepareForCC) {
-      // Unfortunately we need to still mark user data just before running CC so
-      // that it has the right generation.
-      doc->PropertyTable(DOM_USER_DATA)->
-        EnumerateAll(MarkUserData, &nsCCUncollectableMarker::sGeneration);
     }
   }
   if (doc) {
     if (nsPIDOMWindowInner* inner = doc->GetInnerWindow()) {
       inner->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
     }
     if (nsPIDOMWindowOuter* outer = doc->GetWindow()) {
       outer->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
     }
   }
 }
 
-void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS,
-                  bool aPrepareForCC);
+void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS);
 
 void
-MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS, bool aPrepareForCC)
+MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS)
 {
   if (!aSHEntry) {
     return;
   }
 
   nsCOMPtr<nsIContentViewer> cview;
   aSHEntry->GetContentViewer(getter_AddRefs(cview));
-  MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
+  MarkContentViewer(cview, aCleanupJS);
 
   nsCOMPtr<nsIDocShellTreeItem> child;
   int32_t i = 0;
   while (NS_SUCCEEDED(aSHEntry->ChildShellAt(i++, getter_AddRefs(child))) &&
          child) {
-    MarkDocShell(child, aCleanupJS, aPrepareForCC);
+    MarkDocShell(child, aCleanupJS);
   }
 
   nsCOMPtr<nsISHContainer> shCont = do_QueryInterface(aSHEntry);
   int32_t count;
   shCont->GetChildCount(&count);
   for (i = 0; i < count; ++i) {
     nsCOMPtr<nsISHEntry> childEntry;
     shCont->GetChildAt(i, getter_AddRefs(childEntry));
-    MarkSHEntry(childEntry, aCleanupJS, aPrepareForCC);
+    MarkSHEntry(childEntry, aCleanupJS);
   }
 
 }
 
 void
-MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS, bool aPrepareForCC)
+MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS)
 {
   nsCOMPtr<nsIDocShell> shell = do_QueryInterface(aNode);
   if (!shell) {
     return;
   }
 
   nsCOMPtr<nsIContentViewer> cview;
   shell->GetContentViewer(getter_AddRefs(cview));
-  MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
+  MarkContentViewer(cview, aCleanupJS);
 
   nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(shell);
   nsCOMPtr<nsISHistory> history;
   webNav->GetSessionHistory(getter_AddRefs(history));
   if (history) {
     int32_t i, historyCount;
     history->GetCount(&historyCount);
     for (i = 0; i < historyCount; ++i) {
       nsCOMPtr<nsISHEntry> shEntry;
       history->GetEntryAtIndex(i, false, getter_AddRefs(shEntry));
 
-      MarkSHEntry(shEntry, aCleanupJS, aPrepareForCC);
+      MarkSHEntry(shEntry, aCleanupJS);
     }
   }
 
   int32_t i, childCount;
   aNode->GetChildCount(&childCount);
   for (i = 0; i < childCount; ++i) {
     nsCOMPtr<nsIDocShellTreeItem> child;
     aNode->GetChildAt(i, getter_AddRefs(child));
-    MarkDocShell(child, aCleanupJS, aPrepareForCC);
+    MarkDocShell(child, aCleanupJS);
   }
 }
 
 void
-MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS,
-               bool aPrepareForCC)
+MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS)
 {
   nsCOMPtr<nsISupports> iter;
   while (NS_SUCCEEDED(aWindowList->GetNext(getter_AddRefs(iter))) &&
          iter) {
     if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(iter)) {
       nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();
 
-      MarkDocShell(rootDocShell, aCleanupJS, aPrepareForCC);
+      MarkDocShell(rootDocShell, aCleanupJS);
 
       nsCOMPtr<nsITabChild> tabChild =
         rootDocShell ? rootDocShell->GetTabChild() : nullptr;
       if (tabChild) {
         nsCOMPtr<nsIContentFrameMessageManager> mm;
         tabChild->GetMessageManager(getter_AddRefs(mm));
         if (mm) {
           // MarkForCC ends up calling UnmarkGray on message listeners, which
@@ -347,21 +330,21 @@ nsCCUncollectableMarker::Observe(nsISupp
 
     return NS_OK;
   }
 
   NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin") ||
                !strcmp(aTopic, "cycle-collector-forget-skippable"), "wrong topic");
 
   // JS cleanup can be slow. Do it only if there has been a GC.
-  bool cleanupJS =
+  const bool cleanupJS =
     nsJSContext::CleanupsSinceLastGC() == 0 &&
     !strcmp(aTopic, "cycle-collector-forget-skippable");
 
-  bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
+  const bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
   if (prepareForCC) {
     Element::ClearContentUnbinder();
   }
 
   // Increase generation to effectively unmark all current objects
   if (!++sGeneration) {
     ++sGeneration;
   }
@@ -373,46 +356,46 @@ nsCCUncollectableMarker::Observe(nsISupp
   // Iterate all toplevel windows
   nsCOMPtr<nsISimpleEnumerator> windowList;
   nsCOMPtr<nsIWindowMediator> med =
     do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
   if (med) {
     rv = med->GetEnumerator(nullptr, getter_AddRefs(windowList));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    MarkWindowList(windowList, cleanupJS, prepareForCC);
+    MarkWindowList(windowList, cleanupJS);
   }
 
   nsCOMPtr<nsIWindowWatcher> ww =
     do_GetService(NS_WINDOWWATCHER_CONTRACTID);
   if (ww) {
     rv = ww->GetWindowEnumerator(getter_AddRefs(windowList));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    MarkWindowList(windowList, cleanupJS, prepareForCC);
+    MarkWindowList(windowList, cleanupJS);
   }
 
   nsCOMPtr<nsIAppShellService> appShell =
     do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
   if (appShell) {
     nsCOMPtr<nsIXULWindow> hw;
     appShell->GetHiddenWindow(getter_AddRefs(hw));
     if (hw) {
       nsCOMPtr<nsIDocShell> shell;
       hw->GetDocShell(getter_AddRefs(shell));
-      MarkDocShell(shell, cleanupJS, prepareForCC);
+      MarkDocShell(shell, cleanupJS);
     }
     bool hasHiddenPrivateWindow = false;
     appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
     if (hasHiddenPrivateWindow) {
       appShell->GetHiddenPrivateWindow(getter_AddRefs(hw));
       if (hw) {
         nsCOMPtr<nsIDocShell> shell;
         hw->GetDocShell(getter_AddRefs(shell));
-        MarkDocShell(shell, cleanupJS, prepareForCC);
+        MarkDocShell(shell, cleanupJS);
       }
     }
   }
 
 #ifdef MOZ_XUL
   nsXULPrototypeCache* xulCache = nsXULPrototypeCache::GetInstance();
   if (xulCache) {
     xulCache->MarkInCCGeneration(sGeneration);
--- a/dom/base/nsDeprecatedOperationList.h
+++ b/dom/base/nsDeprecatedOperationList.h
@@ -12,17 +12,16 @@
 
 DEPRECATED_OPERATION(EnablePrivilege)
 DEPRECATED_OPERATION(DOMExceptionCode)
 DEPRECATED_OPERATION(MutationEvent)
 DEPRECATED_OPERATION(Components)
 DEPRECATED_OPERATION(PrefixedVisibilityAPI)
 DEPRECATED_OPERATION(NodeIteratorDetach)
 DEPRECATED_OPERATION(LenientThis)
-DEPRECATED_OPERATION(GetSetUserData)
 DEPRECATED_OPERATION(MozGetAsFile)
 DEPRECATED_OPERATION(UseOfCaptureEvents)
 DEPRECATED_OPERATION(UseOfReleaseEvents)
 DEPRECATED_OPERATION(UseOfDOM3LoadMethod)
 DEPRECATED_OPERATION(ChromeUseOfDOM3LoadMethod)
 DEPRECATED_OPERATION(ShowModalDialog)
 DEPRECATED_OPERATION(SyncXMLHttpRequest)
 DEPRECATED_OPERATION(Window_Cc_ontrollers)
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2202,37 +2202,23 @@ nsDocument::Init()
   mozilla::HoldJSObjects(this);
 
   return NS_OK;
 }
 
 void
 nsIDocument::DeleteAllProperties()
 {
-  for (uint32_t i = 0; i < GetPropertyTableCount(); ++i) {
-    PropertyTable(i)->DeleteAllProperties();
-  }
+  PropertyTable().DeleteAllProperties();
 }
 
 void
 nsIDocument::DeleteAllPropertiesFor(nsINode* aNode)
 {
-  for (uint32_t i = 0; i < GetPropertyTableCount(); ++i) {
-    PropertyTable(i)->DeleteAllPropertiesFor(aNode);
-  }
-}
-
-nsPropertyTable*
-nsIDocument::GetExtraPropertyTable(uint16_t aCategory)
-{
-  NS_ASSERTION(aCategory > 0, "Category 0 should have already been handled");
-  while (aCategory >= mExtraPropertyTables.Length() + 1) {
-    mExtraPropertyTables.AppendElement(new nsPropertyTable());
-  }
-  return mExtraPropertyTables[aCategory - 1];
+  PropertyTable().DeleteAllPropertiesFor(aNode);
 }
 
 bool
 nsIDocument::IsVisibleConsideringAncestors() const
 {
   const nsIDocument *parent = this;
   do {
     if (!parent->IsVisible()) {
@@ -7298,38 +7284,30 @@ nsIDocument::AdoptNode(nsINode& aAdopted
   nsNodeUtils::Adopt(adoptedNode, sameDocument ? nullptr : mNodeInfoManager,
                      newScope, nodesWithProperties, rv);
   if (rv.Failed()) {
     // Disconnect all nodes from their parents, since some have the old document
     // as their ownerDocument and some have this as their ownerDocument.
     nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
 
     if (!sameDocument && oldDocument) {
-      uint32_t count = nodesWithProperties.Count();
-      for (uint32_t j = 0; j < oldDocument->GetPropertyTableCount(); ++j) {
-        for (uint32_t i = 0; i < count; ++i) {
-          // Remove all properties.
-          oldDocument->PropertyTable(j)->
-            DeleteAllPropertiesFor(nodesWithProperties[i]);
-        }
+      for (nsINode* node : nodesWithProperties) {
+        // Remove all properties.
+        oldDocument->PropertyTable().DeleteAllPropertiesFor(node);
       }
     }
 
     return nullptr;
   }
 
-  uint32_t count = nodesWithProperties.Count();
   if (!sameDocument && oldDocument) {
-    for (uint32_t j = 0; j < oldDocument->GetPropertyTableCount(); ++j) {
-      nsPropertyTable *oldTable = oldDocument->PropertyTable(j);
-      nsPropertyTable *newTable = PropertyTable(j);
-      for (uint32_t i = 0; i < count; ++i) {
-        rv = oldTable->TransferOrDeleteAllPropertiesFor(nodesWithProperties[i],
-                                                        newTable);
-      }
+    nsPropertyTable& oldTable = oldDocument->PropertyTable();
+    nsPropertyTable& newTable = PropertyTable();
+    for (nsINode* node : nodesWithProperties) {
+      rv = oldTable.TransferOrDeleteAllPropertiesFor(node, newTable);
     }
 
     if (rv.Failed()) {
       // Disconnect all nodes from their parents.
       nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
 
       return nullptr;
     }
@@ -11878,21 +11856,16 @@ nsIDocument::DocAddSizeOfExcludingThis(n
   nsINode::AddSizeOfExcludingThis(aSizes, &aSizes.mDOMOtherSize);
 
   if (mPresShell) {
     mPresShell->AddSizeOfIncludingThis(aSizes);
   }
 
   aSizes.mPropertyTablesSize +=
     mPropertyTable.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
-  for (uint32_t i = 0, count = mExtraPropertyTables.Length();
-       i < count; ++i) {
-    aSizes.mPropertyTablesSize +=
-      mExtraPropertyTables[i]->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
-  }
 
   if (EventListenerManager* elm = GetExistingListenerManager()) {
     aSizes.mDOMEventListenersCount += elm->ListenerCount();
   }
 
   if (mNodeInfoManager) {
     mNodeInfoManager->AddSizeOfIncludingThis(aSizes);
   }
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2284,23 +2284,20 @@ public:
   int32_t GetDefaultNamespaceID() const
   {
     return mDefaultElementType;
   }
 
   void DeleteAllProperties();
   void DeleteAllPropertiesFor(nsINode* aNode);
 
-  nsPropertyTable* PropertyTable(uint16_t aCategory) {
-    if (aCategory == 0)
-      return &mPropertyTable;
-    return GetExtraPropertyTable(aCategory);
-  }
-  uint32_t GetPropertyTableCount()
-  { return mExtraPropertyTables.Length() + 1; }
+  nsPropertyTable& PropertyTable()
+  {
+    return mPropertyTable;
+  }
 
   /**
    * Sets the ID used to identify this part of the multipart document
    */
   void SetPartID(uint32_t aID) {
     mPartID = aID;
   }
 
@@ -3802,17 +3799,16 @@ protected:
   {
     if (--mStackRefCnt == 0 && mNeedsReleaseAfterStackRefCntRelease) {
       mNeedsReleaseAfterStackRefCntRelease = false;
       NS_RELEASE_THIS();
     }
   }
 
   ~nsIDocument();
-  nsPropertyTable* GetExtraPropertyTable(uint16_t aCategory);
 
   // Never ever call this. Only call GetWindow!
   nsPIDOMWindowOuter* GetWindowInternal() const;
 
   // Never ever call this. Only call GetScriptHandlingObject!
   nsIScriptGlobalObject* GetScriptHandlingObjectInternal() const;
 
   // Never ever call this. Only call AllowXULXBL!
@@ -3944,17 +3940,16 @@ protected:
 
   LinksToUpdateList mLinksToUpdate;
 
   // SMIL Animation Controller, lazily-initialized in GetAnimationController
   RefPtr<nsSMILAnimationController> mAnimationController;
 
   // Table of element properties for this document.
   nsPropertyTable mPropertyTable;
-  nsTArray<nsAutoPtr<nsPropertyTable> > mExtraPropertyTables;
 
   // Our cached .children collection
   nsCOMPtr<nsIHTMLCollection> mChildrenCollection;
 
   // Various DOM lists
   RefPtr<nsContentList> mImages;
   RefPtr<nsContentList> mEmbeds;
   RefPtr<nsContentList> mLinks;
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -160,60 +160,56 @@ nsINode::nsSlots::Unlink()
 
 nsINode::~nsINode()
 {
   MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
   MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?");
 }
 
 void*
-nsINode::GetProperty(uint16_t aCategory, nsAtom *aPropertyName,
-                     nsresult *aStatus) const
+nsINode::GetProperty(nsAtom* aPropertyName, nsresult* aStatus) const
 {
   if (!HasProperties()) { // a fast HasFlag() test
     if (aStatus) {
       *aStatus = NS_PROPTABLE_PROP_NOT_THERE;
     }
     return nullptr;
   }
-  return OwnerDoc()->PropertyTable(aCategory)->GetProperty(this, aPropertyName,
-                                                           aStatus);
+  return OwnerDoc()->PropertyTable().GetProperty(this, aPropertyName, aStatus);
 }
 
 nsresult
-nsINode::SetProperty(uint16_t aCategory, nsAtom *aPropertyName, void *aValue,
-                     NSPropertyDtorFunc aDtor, bool aTransfer,
-                     void **aOldValue)
+nsINode::SetProperty(nsAtom* aPropertyName,
+                     void* aValue,
+                     NSPropertyDtorFunc aDtor,
+                     bool aTransfer)
 {
-  nsresult rv = OwnerDoc()->PropertyTable(aCategory)->SetProperty(this,
-                                                                  aPropertyName,
-                                                                  aValue, aDtor,
-                                                                  nullptr,
-                                                                  aTransfer,
-                                                                  aOldValue);
+  nsresult rv = OwnerDoc()->PropertyTable().SetProperty(this,
+                                                        aPropertyName,
+                                                        aValue,
+                                                        aDtor,
+                                                        nullptr,
+                                                        aTransfer);
   if (NS_SUCCEEDED(rv)) {
     SetFlags(NODE_HAS_PROPERTIES);
   }
 
   return rv;
 }
 
 void
-nsINode::DeleteProperty(uint16_t aCategory, nsAtom *aPropertyName)
+nsINode::DeleteProperty(nsAtom* aPropertyName)
 {
-  OwnerDoc()->PropertyTable(aCategory)->DeleteProperty(this, aPropertyName);
+  OwnerDoc()->PropertyTable().DeleteProperty(this, aPropertyName);
 }
 
 void*
-nsINode::UnsetProperty(uint16_t aCategory, nsAtom *aPropertyName,
-                       nsresult *aStatus)
+nsINode::UnsetProperty(nsAtom* aPropertyName, nsresult* aStatus)
 {
-  return OwnerDoc()->PropertyTable(aCategory)->UnsetProperty(this,
-                                                             aPropertyName,
-                                                             aStatus);
+  return OwnerDoc()->PropertyTable().UnsetProperty(this, aPropertyName, aStatus);
 }
 
 nsINode::nsSlots*
 nsINode::CreateSlots()
 {
   return new nsSlots();
 }
 
@@ -731,113 +727,16 @@ nsINode::LookupPrefix(const nsAString& a
         }
       }
     }
   }
 
   SetDOMStringToNull(aPrefix);
 }
 
-static nsresult
-SetUserDataProperty(uint16_t aCategory, nsINode *aNode, nsAtom *aKey,
-                    nsISupports* aValue, void** aOldValue)
-{
-  nsresult rv = aNode->SetProperty(aCategory, aKey, aValue,
-                                   nsPropertyTable::SupportsDtorFunc, true,
-                                   aOldValue);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Property table owns it now.
-  NS_ADDREF(aValue);
-
-  return NS_OK;
-}
-
-nsresult
-nsINode::SetUserData(const nsAString &aKey, nsIVariant *aData, nsIVariant **aResult)
-{
-  OwnerDoc()->WarnOnceAbout(nsIDocument::eGetSetUserData);
-  *aResult = nullptr;
-
-  RefPtr<nsAtom> key = NS_Atomize(aKey);
-  if (!key) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  nsresult rv;
-  void *data;
-  if (aData) {
-    rv = SetUserDataProperty(DOM_USER_DATA, this, key, aData, &data);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else {
-    data = UnsetProperty(DOM_USER_DATA, key);
-  }
-
-  // Take over ownership of the old data from the property table.
-  nsCOMPtr<nsIVariant> oldData = dont_AddRef(static_cast<nsIVariant*>(data));
-  oldData.swap(*aResult);
-  return NS_OK;
-}
-
-void
-nsINode::SetUserData(JSContext* aCx, const nsAString& aKey,
-                     JS::Handle<JS::Value> aData,
-                     JS::MutableHandle<JS::Value> aRetval,
-                     ErrorResult& aError)
-{
-  nsCOMPtr<nsIVariant> data;
-  aError = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData, getter_AddRefs(data));
-  if (aError.Failed()) {
-    return;
-  }
-
-  nsCOMPtr<nsIVariant> oldData;
-  aError = SetUserData(aKey, data, getter_AddRefs(oldData));
-  if (aError.Failed()) {
-    return;
-  }
-
-  if (!oldData) {
-    aRetval.setNull();
-    return;
-  }
-
-  JSAutoCompartment ac(aCx, GetWrapper());
-  aError = nsContentUtils::XPConnect()->VariantToJS(aCx, GetWrapper(), oldData,
-                                                    aRetval);
-}
-
-nsIVariant*
-nsINode::GetUserData(const nsAString& aKey)
-{
-  OwnerDoc()->WarnOnceAbout(nsIDocument::eGetSetUserData);
-  RefPtr<nsAtom> key = NS_Atomize(aKey);
-  if (!key) {
-    return nullptr;
-  }
-
-  return static_cast<nsIVariant*>(GetProperty(DOM_USER_DATA, key));
-}
-
-void
-nsINode::GetUserData(JSContext* aCx, const nsAString& aKey,
-                     JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
-{
-  nsIVariant* data = GetUserData(aKey);
-  if (!data) {
-    aRetval.setNull();
-    return;
-  }
-
-  JSAutoCompartment ac(aCx, GetWrapper());
-  aError = nsContentUtils::XPConnect()->VariantToJS(aCx, GetWrapper(), data,
-                                                    aRetval);
-}
-
 uint16_t
 nsINode::CompareDocumentPosition(nsINode& aOtherNode) const
 {
   if (this == &aOtherNode) {
     return 0;
   }
   if (GetPreviousSibling() == &aOtherNode) {
     MOZ_ASSERT(GetParentNode() == aOtherNode.GetParentNode());
@@ -1407,17 +1306,16 @@ nsINode::Traverse(nsINode *tmp, nsCycleC
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
 
   nsSlots *slots = tmp->GetExistingSlots();
   if (slots) {
     slots->Traverse(cb);
   }
 
   if (tmp->HasProperties()) {
-    nsNodeUtils::TraverseUserData(tmp, cb);
     nsCOMArray<nsISupports>* objects =
       static_cast<nsCOMArray<nsISupports>*>(tmp->GetProperty(nsGkAtoms::keepobjectsalive));
     if (objects) {
       for (int32_t i = 0; i < objects->Count(); ++i) {
          cb.NoteXPCOMChild(objects->ObjectAt(i));
       }
     }
   }
@@ -1443,17 +1341,16 @@ nsINode::Unlink(nsINode* tmp)
 
   if (tmp->NodeType() != DOCUMENT_NODE &&
       tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
     nsContentUtils::RemoveListenerManager(tmp);
     tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
   }
 
   if (tmp->HasProperties()) {
-    nsNodeUtils::UnlinkUserData(tmp);
     tmp->DeleteProperty(nsGkAtoms::keepobjectsalive);
   }
 }
 
 static void
 AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode, ErrorResult& aError)
 {
   NS_ASSERTION(!aNode->GetParentNode(),
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -268,20 +268,16 @@ private:
 // This should be used for any nsINode sub-class that has fields of its own
 // that it needs to measure; any sub-class that doesn't use it will inherit
 // AddSizeOfExcludingThis from its super-class. AddSizeOfIncludingThis() need
 // not be defined, it is inherited from nsINode.
 #define NS_DECL_ADDSIZEOFEXCLUDINGTHIS \
   virtual void AddSizeOfExcludingThis(nsWindowSizes& aSizes, \
                                       size_t* aNodeSize) const override;
 
-// Categories of node properties
-// 0 is global.
-#define DOM_USER_DATA         1
-
 // IID for the nsINode interface
 // Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs
 #define NS_INODE_IID \
 { 0x70ba4547, 0x7699, 0x44fc, \
   { 0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a } }
 
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
@@ -839,36 +835,17 @@ public:
    * @param aPropertyName  name of property to get.
    * @param aStatus        out parameter for storing resulting status.
    *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
    *                       is not set.
    * @return               the property. Null if the property is not set
    *                       (though a null return value does not imply the
    *                       property was not set, i.e. it can be set to null).
    */
-  void* GetProperty(nsAtom *aPropertyName,
-                    nsresult *aStatus = nullptr) const
-  {
-    return GetProperty(0, aPropertyName, aStatus);
-  }
-
-  /**
-   * Get a property associated with this node.
-   *
-   * @param aCategory      category of property to get.
-   * @param aPropertyName  name of property to get.
-   * @param aStatus        out parameter for storing resulting status.
-   *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
-   *                       is not set.
-   * @return               the property. Null if the property is not set
-   *                       (though a null return value does not imply the
-   *                       property was not set, i.e. it can be set to null).
-   */
-  void* GetProperty(uint16_t aCategory, nsAtom *aPropertyName,
-                    nsresult *aStatus = nullptr) const;
+  void* GetProperty(nsAtom* aPropertyName, nsresult* aStatus = nullptr) const;
 
   /**
    * Set a property to be associated with this node. This will overwrite an
    * existing value if one exists. The existing value is destroyed using the
    * destructor function given when that value was set.
    *
    * @param aPropertyName  name of property to set.
    * @param aValue         new value of property.
@@ -877,112 +854,52 @@ public:
    * @param aTransfer      if true the property will not be deleted when the
    *                       ownerDocument of the node changes, if false it
    *                       will be deleted.
    *
    * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property
    *                                       was already set
    * @throws NS_ERROR_OUT_OF_MEMORY if that occurs
    */
-  nsresult SetProperty(nsAtom *aPropertyName, void *aValue,
+  nsresult SetProperty(nsAtom* aPropertyName,
+                       void* aValue,
                        NSPropertyDtorFunc aDtor = nullptr,
-                       bool aTransfer = false)
-  {
-    return SetProperty(0, aPropertyName, aValue, aDtor, aTransfer);
-  }
-
-  /**
-   * Set a property to be associated with this node. This will overwrite an
-   * existing value if one exists. The existing value is destroyed using the
-   * destructor function given when that value was set.
-   *
-   * @param aCategory       category of property to set.
-   * @param aPropertyName   name of property to set.
-   * @param aValue          new value of property.
-   * @param aDtor           destructor function to be used when this property
-   *                        is destroyed.
-   * @param aTransfer       if true the property will not be deleted when the
-   *                        ownerDocument of the node changes, if false it
-   *                        will be deleted.
-   * @param aOldValue [out] previous value of property.
-   *
-   * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property
-   *                                       was already set
-   * @throws NS_ERROR_OUT_OF_MEMORY if that occurs
-   */
-  nsresult SetProperty(uint16_t aCategory,
-                       nsAtom *aPropertyName, void *aValue,
-                       NSPropertyDtorFunc aDtor = nullptr,
-                       bool aTransfer = false,
-                       void **aOldValue = nullptr);
+                       bool aTransfer = false);
 
   /**
    * A generic destructor for property values allocated with new.
    */
   template<class T>
-  static void DeleteProperty(void *, nsAtom *, void *aPropertyValue, void *)
+  static void DeleteProperty(void*, nsAtom*, void* aPropertyValue, void*)
   {
     delete static_cast<T *>(aPropertyValue);
   }
 
   /**
    * Destroys a property associated with this node. The value is destroyed
    * using the destruction function given when that value was set.
    *
    * @param aPropertyName  name of property to destroy.
    */
-  void DeleteProperty(nsAtom *aPropertyName)
-  {
-    DeleteProperty(0, aPropertyName);
-  }
-
-  /**
-   * Destroys a property associated with this node. The value is destroyed
-   * using the destruction function given when that value was set.
-   *
-   * @param aCategory      category of property to destroy.
-   * @param aPropertyName  name of property to destroy.
-   */
-  void DeleteProperty(uint16_t aCategory, nsAtom *aPropertyName);
+  void DeleteProperty(nsAtom* aPropertyName);
 
   /**
    * Unset a property associated with this node. The value will not be
    * destroyed but rather returned. It is the caller's responsibility to
    * destroy the value after that point.
    *
    * @param aPropertyName  name of property to unset.
    * @param aStatus        out parameter for storing resulting status.
    *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
    *                       is not set.
    * @return               the property. Null if the property is not set
    *                       (though a null return value does not imply the
    *                       property was not set, i.e. it can be set to null).
    */
-  void* UnsetProperty(nsAtom  *aPropertyName,
-                      nsresult *aStatus = nullptr)
-  {
-    return UnsetProperty(0, aPropertyName, aStatus);
-  }
-
-  /**
-   * Unset a property associated with this node. The value will not be
-   * destroyed but rather returned. It is the caller's responsibility to
-   * destroy the value after that point.
-   *
-   * @param aCategory      category of property to unset.
-   * @param aPropertyName  name of property to unset.
-   * @param aStatus        out parameter for storing resulting status.
-   *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
-   *                       is not set.
-   * @return               the property. Null if the property is not set
-   *                       (though a null return value does not imply the
-   *                       property was not set, i.e. it can be set to null).
-   */
-  void* UnsetProperty(uint16_t aCategory, nsAtom *aPropertyName,
-                      nsresult *aStatus = nullptr);
+  void* UnsetProperty(nsAtom* aPropertyName, nsresult* aStatus = nullptr);
 
   bool HasProperties() const
   {
     return HasFlag(NODE_HAS_PROPERTIES);
   }
 
   /**
    * Return the principal of this node.  This is guaranteed to never be a null
@@ -1446,41 +1363,16 @@ public:
   already_AddRefed<nsINodeList> QuerySelectorAll(const nsAString& aSelector,
                                                  mozilla::ErrorResult& aResult);
 
 protected:
   // nsIDocument overrides this with its own (faster) version.  This
   // should really only be called for elements and document fragments.
   mozilla::dom::Element* GetElementById(const nsAString& aId);
 
-  /**
-   * Associate an object aData to aKey on this node. If aData is null any
-   * previously registered object associated to aKey on this node will
-   * be removed.
-   * Should only be used to implement the DOM Level 3 UserData API.
-   *
-   * @param aKey the key to associate the object to
-   * @param aData the object to associate to aKey on this node (may be null)
-   * @param aResult [out] the previously registered object for aKey on this
-   *                      node, if any
-   * @return whether adding the object succeeded
-   */
-  nsresult SetUserData(const nsAString& aKey, nsIVariant* aData,
-                       nsIVariant** aResult);
-
-  /**
-   * Get the UserData object registered for a Key on this node, if any.
-   * Should only be used to implement the DOM Level 3 UserData API.
-   *
-   * @param aKey the key to get UserData for
-   * @return aResult the previously registered object for aKey on this node, if
-   *                 any
-   */
-  nsIVariant* GetUserData(const nsAString& aKey);
-
 public:
   void LookupPrefix(const nsAString& aNamespace, nsAString& aResult);
   bool IsDefaultNamespace(const nsAString& aNamespaceURI)
   {
     nsAutoString defaultNamespace;
     LookupNamespaceURI(EmptyString(), defaultNamespace);
     return aNamespaceURI.Equals(defaultNamespace);
   }
@@ -1939,23 +1831,16 @@ public:
 #endif
   void GetLocalName(mozilla::dom::DOMString& aLocalName) const
   {
     const nsString& localName = LocalName();
     aLocalName.SetKnownLiveString(localName);
   }
 
   nsDOMAttributeMap* GetAttributes();
-  void SetUserData(JSContext* aCx, const nsAString& aKey,
-                   JS::Handle<JS::Value> aData,
-                   JS::MutableHandle<JS::Value> aRetval,
-                   mozilla::ErrorResult& aError);
-  void GetUserData(JSContext* aCx, const nsAString& aKey,
-                   JS::MutableHandle<JS::Value> aRetval,
-                   mozilla::ErrorResult& aError);
 
   // Helper method to remove this node from its parent. This is not exposed
   // through WebIDL.
   // Only call this if the node has a parent node.
   nsresult RemoveFromParent()
   {
     nsINode* parent = GetParentNode();
     mozilla::ErrorResult rv;
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -365,34 +365,16 @@ nsNodeUtils::LastRelease(nsINode* aNode)
                  "Node has binding on destruction");
   }
 
   aNode->ReleaseWrapper(aNode);
 
   FragmentOrElement::RemoveBlackMarkedNode(aNode);
 }
 
-static void
-NoteUserData(void *aObject, nsAtom *aKey, void *aXPCOMChild, void *aData)
-{
-  nsCycleCollectionTraversalCallback* cb =
-    static_cast<nsCycleCollectionTraversalCallback*>(aData);
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "[user data]");
-  cb->NoteXPCOMChild(static_cast<nsISupports*>(aXPCOMChild));
-}
-
-/* static */
-void
-nsNodeUtils::TraverseUserData(nsINode* aNode,
-                              nsCycleCollectionTraversalCallback &aCb)
-{
-  nsIDocument* ownerDoc = aNode->OwnerDoc();
-  ownerDoc->PropertyTable(DOM_USER_DATA)->Enumerate(aNode, NoteUserData, &aCb);
-}
-
 /* static */
 already_AddRefed<nsINode>
 nsNodeUtils::CloneNodeImpl(nsINode *aNode, bool aDeep, ErrorResult& aError)
 {
   return Clone(aNode, aDeep, nullptr, nullptr, aError);
 }
 
 /* static */
@@ -711,29 +693,16 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
         return nullptr;
       }
     }
   }
 
   return clone.forget();
 }
 
-
-/* static */
-void
-nsNodeUtils::UnlinkUserData(nsINode *aNode)
-{
-  NS_ASSERTION(aNode->HasProperties(), "Call to UnlinkUserData not needed.");
-
-  // Strong reference to the document so that deleting properties can't
-  // delete the document.
-  nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
-  document->PropertyTable(DOM_USER_DATA)->DeleteAllPropertiesFor(aNode);
-}
-
 bool
 nsNodeUtils::IsTemplateElement(const nsINode *aNode)
 {
   return aNode->IsHTMLElement(nsGkAtoms::_template);
 }
 
 nsIContent*
 nsNodeUtils::GetFirstChildOfTemplateOrNode(nsINode* aNode)
--- a/dom/base/nsNodeUtils.h
+++ b/dom/base/nsNodeUtils.h
@@ -220,45 +220,29 @@ public:
     nsCOMPtr<nsINode> node = CloneAndAdopt(aNode, false, true, aNewNodeInfoManager,
                                            aReparentScope, &aNodesWithProperties,
                                            nullptr, aError);
 
     nsMutationGuard::DidMutate();
   }
 
   /**
-   * Helper for the cycle collector to traverse the DOM UserData for aNode.
-   *
-   * @param aNode the node to traverse UserData for
-   * @param aCb the cycle collection callback
-   */
-  static void TraverseUserData(nsINode* aNode,
-                               nsCycleCollectionTraversalCallback &aCb);
-
-  /**
    * A basic implementation of the DOM cloneNode method. Calls nsINode::Clone to
    * do the actual cloning of the node.
    *
    * @param aNode the node to clone
    * @param aDeep if true all descendants will be cloned too
    * @param aError the error, if any.
    *
    * @return the clone, or null if an error occurs.
    */
   static already_AddRefed<nsINode> CloneNodeImpl(nsINode *aNode, bool aDeep,
                                                  mozilla::ErrorResult& aError);
 
   /**
-   * Release the UserData for aNode.
-   *
-   * @param aNode the node to release the UserData for
-   */
-  static void UnlinkUserData(nsINode *aNode);
-
-  /**
    * Returns a true if the node is a HTMLTemplate element.
    *
    * @param aNode a node to test for HTMLTemplate elementness.
    */
   static bool IsTemplateElement(const nsINode *aNode);
 
   /**
    * Returns the first child of a node or the first child of
--- a/dom/base/nsPropertyTable.cpp
+++ b/dom/base/nsPropertyTable.cpp
@@ -75,38 +75,36 @@ nsPropertyTable::DeleteAllPropertiesFor(
 {
   for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
     prop->DeletePropertyFor(aObject);
   }
 }
 
 nsresult
 nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
-                                                  nsPropertyTable *aOtherTable)
+                                                  nsPropertyTable& aOtherTable)
 {
   nsresult rv = NS_OK;
   for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
     if (prop->mTransfer) {
       auto entry = static_cast<PropertyListMapEntry*>
                               (prop->mObjectValueMap.Search(aObject));
       if (entry) {
-        rv = aOtherTable->SetProperty(aObject, prop->mName,
-                                      entry->value, prop->mDtorFunc,
-                                      prop->mDtorData, prop->mTransfer);
+        rv = aOtherTable.SetProperty(aObject, prop->mName,
+                                     entry->value, prop->mDtorFunc,
+                                     prop->mDtorData, prop->mTransfer);
         if (NS_FAILED(rv)) {
           DeleteAllPropertiesFor(aObject);
-          aOtherTable->DeleteAllPropertiesFor(aObject);
-
+          aOtherTable.DeleteAllPropertiesFor(aObject);
           break;
         }
 
         prop->mObjectValueMap.RemoveEntry(entry);
       }
-    }
-    else {
+    } else {
       prop->DeletePropertyFor(aObject);
     }
   }
 
   return rv;
 }
 
 void
@@ -133,19 +131,19 @@ nsPropertyTable::EnumerateAll(NSProperty
       aCallBack(const_cast<void*>(entry->key), prop->mName, entry->value,
                 aData);
     }
   }
 }
 
 void*
 nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
-                                     nsAtom    *aPropertyName,
-                                     bool        aRemove,
-                                     nsresult   *aResult)
+                                     nsAtom* aPropertyName,
+                                     bool aRemove,
+                                     nsresult* aResult)
 {
   NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
   nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
   void *propValue = nullptr;
 
   PropertyList* propertyList = GetPropertyListFor(aPropertyName);
   if (propertyList) {
     auto entry = static_cast<PropertyListMapEntry*>
@@ -162,23 +160,22 @@ nsPropertyTable::GetPropertyInternal(nsP
 
   if (aResult)
     *aResult = rv;
 
   return propValue;
 }
 
 nsresult
-nsPropertyTable::SetPropertyInternal(nsPropertyOwner     aObject,
-                                     nsAtom            *aPropertyName,
-                                     void               *aPropertyValue,
-                                     NSPropertyDtorFunc  aPropDtorFunc,
-                                     void               *aPropDtorData,
-                                     bool                aTransfer,
-                                     void              **aOldValue)
+nsPropertyTable::SetPropertyInternal(nsPropertyOwner aObject,
+                                     nsAtom* aPropertyName,
+                                     void* aPropertyValue,
+                                     NSPropertyDtorFunc aPropDtorFunc,
+                                     void* aPropDtorData,
+                                     bool aTransfer)
 {
   NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
 
   PropertyList* propertyList = GetPropertyListFor(aPropertyName);
 
   if (propertyList) {
     // Make sure the dtor function and data and the transfer flag match
     if (aPropDtorFunc != propertyList->mDtorFunc ||
@@ -200,35 +197,31 @@ nsPropertyTable::SetPropertyInternal(nsP
   nsresult result = NS_OK;
   auto entry = static_cast<PropertyListMapEntry*>
     (propertyList->mObjectValueMap.Add(aObject, mozilla::fallible));
   if (!entry)
     return NS_ERROR_OUT_OF_MEMORY;
   // A nullptr entry->key is the sign that the entry has just been allocated
   // for us.  If it's non-nullptr then we have an existing entry.
   if (entry->key) {
-    if (aOldValue)
-      *aOldValue = entry->value;
-    else if (propertyList->mDtorFunc)
+    if (propertyList->mDtorFunc) {
       propertyList->mDtorFunc(const_cast<void*>(entry->key), aPropertyName,
                               entry->value, propertyList->mDtorData);
+    }
     result = NS_PROPTABLE_PROP_OVERWRITTEN;
   }
-  else if (aOldValue) {
-    *aOldValue = nullptr;
-  }
   entry->key = aObject;
   entry->value = aPropertyValue;
 
   return result;
 }
 
 nsresult
 nsPropertyTable::DeleteProperty(nsPropertyOwner aObject,
-                                nsAtom    *aPropertyName)
+                                nsAtom* aPropertyName)
 {
   NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
 
   PropertyList* propertyList = GetPropertyListFor(aPropertyName);
   if (propertyList) {
     if (propertyList->DeletePropertyFor(aObject))
       return NS_OK;
   }
--- a/dom/base/nsPropertyTable.h
+++ b/dom/base/nsPropertyTable.h
@@ -70,52 +70,48 @@ class nsPropertyTable
   /**
    * Set the value of the property |aPropertyName| to
    * |aPropertyValue| for node |aObject|.  |aDtor| is a destructor for the
    * property value to be called if the property is removed.  It can be null
    * if no destructor is required.  |aDtorData| is an optional pointer to an
    * opaque context to be passed to the property destructor.  Note that the
    * destructor is global for each property name regardless of node; it is an
    * error to set a given property with a different destructor than was used
-   * before (this will return NS_ERROR_INVALID_ARG). If aOldValue is non-null
-   * it will contain the old value after the function returns (the destructor
-   * for the old value will not be run in that case). If |aTransfer| is true
+   * before (this will return NS_ERROR_INVALID_ARG). If |aTransfer| is true
    * the property will be transfered to the new table when the property table
    * for |aObject| changes (currently the tables for nodes are owned by their
    * ownerDocument, so if the ownerDocument for a node changes, its property
    * table changes too). If |aTransfer| is false the property will just be
    * deleted instead.
    */
-  nsresult SetProperty(const nsPropertyOwner&     aObject,
-                                   nsAtom            *aPropertyName,
-                                   void               *aPropertyValue,
-                                   NSPropertyDtorFunc  aDtor,
-                                   void               *aDtorData,
-                                   bool                aTransfer = false,
-                                   void              **aOldValue = nullptr)
+  nsresult SetProperty(const nsPropertyOwner& aObject,
+                       nsAtom* aPropertyName,
+                       void* aPropertyValue,
+                       NSPropertyDtorFunc aDtor,
+                       void* aDtorData,
+                       bool aTransfer = false)
   {
     return SetPropertyInternal(aObject, aPropertyName, aPropertyValue,
-                               aDtor, aDtorData, aTransfer, aOldValue);
+                               aDtor, aDtorData, aTransfer);
   }
 
   /**
    * Delete the property |aPropertyName| in the global category for object
    * |aObject|. The property's destructor function will be called.
    */
-  nsresult DeleteProperty(nsPropertyOwner aObject,
-                                      nsAtom    *aPropertyName);
+  nsresult DeleteProperty(nsPropertyOwner aObject, nsAtom* aPropertyName);
 
   /**
    * Unset the property |aPropertyName| in the global category for object
    * |aObject|, but do not call the property's destructor function.  The
    * property value is returned.
    */
   void* UnsetProperty(const nsPropertyOwner& aObject,
-                      nsAtom    *aPropertyName,
-                      nsresult   *aStatus = nullptr)
+                      nsAtom* aPropertyName,
+                      nsresult* aStatus = nullptr)
   {
     return GetPropertyInternal(aObject, aPropertyName, true, aStatus);
   }
 
   /**
    * Deletes all of the properties for object |aObject|, calling the
    * destructor function for each property.
    */
@@ -123,27 +119,25 @@ class nsPropertyTable
 
   /**
    * Transfers all properties for object |aObject| that were set with the
    * |aTransfer| argument as true to |aTable|. Deletes the other properties
    * for object |aObject|, calling the destructor function for each property.
    * If transfering a property fails, this deletes all the properties for
    * object |aObject|.
    */
-  nsresult
-    TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
-                                     nsPropertyTable *aOtherTable);
+  nsresult TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
+                                            nsPropertyTable& aOtherTable);
 
   /**
    * Enumerate the properties for object |aObject|.
    * For every property |aCallback| will be called with as arguments |aObject|,
    * the property name, the property value and |aData|.
    */
-  void Enumerate(nsPropertyOwner aObject,
-                             NSPropertyFunc aCallback, void *aData);
+  void Enumerate(nsPropertyOwner aObject, NSPropertyFunc aCallback, void* aData);
 
   /**
    * Enumerate all the properties.
    * For every property |aCallback| will be called with arguments the owner,
    * the property name, the property value and |aData|.
    */
   void EnumerateAll(NSPropertyFunc aCallback, void *aData);
 
@@ -168,24 +162,23 @@ class nsPropertyTable
 
   class PropertyList;
 
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
  private:
   void DestroyPropertyList();
-  PropertyList* GetPropertyListFor(nsAtom *aPropertyName) const;
+  PropertyList* GetPropertyListFor(nsAtom* aPropertyName) const;
   void* GetPropertyInternal(nsPropertyOwner aObject,
-                                        nsAtom    *aPropertyName,
-                                        bool        aRemove,
-                                        nsresult   *aStatus);
-  nsresult SetPropertyInternal(nsPropertyOwner     aObject,
-                                           nsAtom            *aPropertyName,
-                                           void               *aPropertyValue,
-                                           NSPropertyDtorFunc  aDtor,
-                                           void               *aDtorData,
-                                           bool                aTransfer,
-                                           void              **aOldValue);
+                            nsAtom* aPropertyName,
+                            bool aRemove,
+                            nsresult* aStatus);
+  nsresult SetPropertyInternal(nsPropertyOwner aObject,
+                               nsAtom* aPropertyName,
+                               void* aPropertyValue,
+                               NSPropertyDtorFunc  aDtor,
+                               void* aDtorData,
+                               bool aTransfer);
 
   PropertyList *mPropertyList;
 };
 #endif
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -802,11 +802,10 @@ tags = audiochannel
 [test_window_keys.html]
 [test_window_named_frame_enumeration.html]
 [test_window_orientation.html]
 skip-if = true # bug 1312417
 [test_window_own_props.html]
 [test_window_proto.html]
 [test_writable-replaceable.html]
 [test_x-frame-options.html]
-[test_xbl_userdata.xhtml]
 [test_youtube_flash_embed.html]
 # Please keep alphabetical order.
--- a/dom/base/test/test_bug548463.html
+++ b/dom/base/test/test_bug548463.html
@@ -55,29 +55,12 @@ frag.appendChild(elem1);
 frag.appendChild(elem2);
 testAdoptFromDOMNodeRemoved(frag, elem1, elem2);
 
 content.appendChild(elem1);
 testAdoptFromDOMNodeRemoved(elem1, elem1, content);
 
 content.appendChild(elem1);
 
-var thrown = false;
-
-function changeOwnerDocument()
-{
-  SpecialPowers.wrap(elem1).setUserData("foo", null, null);
-  otherDoc.adoptNode(elem1);
-}
-SpecialPowers.wrap(elem1).setUserData("foo", "bar", changeOwnerDocument);
-try {
-  document.adoptNode(elem1);
-}
-catch (e) {
-  thrown = true;
-}
-
-ok(!thrown, "adoptNode while adopting should not throw");
-
 </script>
 </pre>
 </body>
 </html>
deleted file mode 100644
--- a/dom/base/test/test_xbl_userdata.xhtml
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE HTML>
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>Test for getUserData/setUserData support in XBL</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-
-<style type="text/css">
-#t {
--moz-binding: url(#xbl);
-}
-</style>
-
-<bindings xmlns="http://www.mozilla.org/xbl">
-<binding id="xbl" inheritstyle="false">
-<implementation><constructor><![CDATA[
-  this.textContent = !!(this.getUserData && this.setUserData);
-]]></constructor></implementation>
-</binding>
-</bindings>
-
-</head>
-<body>
-<p id="display"></p>
-
-<pre id="test">
-<script class="testbody">
-<![CDATA[
-"use strict";
-
-var url = '<div id=t style="-moz-binding:url(' + location + '#xbl)"></div>';
-
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(test1);
-
-function test1() {
-  var iframe = document.createElement('iframe');
-  iframe.srcdoc = url;
-  iframe.onload = function() {
-    var t = iframe.contentWindow.t;
-    is(!!(t.getUserData || t.setUserData), false,
-       "getUserData and setUserData should not be visible from the regular content");
-    is(t.textContent, "true",
-       "getUserData and setUserData should be visible from XBL");
-    document.body.removeChild(iframe);
-    SimpleTest.finish();
-  };
-  document.body.appendChild(iframe);
-}
-
-]]>
-</script>
-</pre>
-</body>
-</html>
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -94,20 +94,16 @@ interface Node : EventTarget {
   [Pure]
   DOMString? lookupPrefix(DOMString? namespace);
   [Pure]
   DOMString? lookupNamespaceURI(DOMString? prefix);
   [Pure]
   boolean isDefaultNamespace(DOMString? namespace);
 
   // Mozilla-specific stuff
-  [Throws, Func="IsChromeOrXBL"]
-  any setUserData(DOMString key, any data);
-  [Throws, Func="IsChromeOrXBL"]
-  any getUserData(DOMString key);
   [ChromeOnly]
   readonly attribute Principal nodePrincipal;
   [ChromeOnly]
   readonly attribute URI? baseURIObject;
   [ChromeOnly]
   sequence<MutationObserver> getBoundMutationObservers();
   [ChromeOnly]
   DOMString generateXPath();
deleted file mode 100644
--- a/js/xpconnect/crashtests/462926.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script type="text/javascript">
-
-try { document.createTextNode("").getUserData.call(0, 0); } catch(e) { }
-
-</script>
-</head>
-<body>
-</body>
-</html>
--- a/js/xpconnect/crashtests/crashtests.list
+++ b/js/xpconnect/crashtests/crashtests.list
@@ -8,17 +8,16 @@ load 346512-1.xhtml
 load 382133-1.html
 load 386680-1.html
 load 394810-1.html
 load 400349-1.html
 load 403356-1.html
 load 418139-1.svg
 load 420513-1.html
 load 453935-1.html
-load 462926.html
 load 467693-1.html
 load 468552-1.html
 load 471366-1.html
 load 475185-1.html
 load 475291-1.html
 load 503286-1.html
 load 504000-1.html
 load 509075-1.html
--- a/js/xpconnect/tests/chrome/test_weakmaps.xul
+++ b/js/xpconnect/tests/chrome/test_weakmaps.xul
@@ -44,17 +44,23 @@ https://bugzilla.mozilla.org/show_bug.cg
   values reachable only from XPConnect must be marked gray for this to work, and the cycle collector
   must know the proper structure of the heap.
 
   */
   let make_gray_loop = function () {
     let map = new WeakMap;
     let div = document.createElement("div");
     let key = {};
-    div.setUserData("entrain", {m:map, k:key}, null);
+    let obj = {m:map, k:key};
+    div.addEventListener("foo", function() {
+      // The code below doesn't matter (it won't run). Just pull a
+      // reference to obj.
+      obj.k = 1;
+      obj.m = "bar";
+    });
     //div.entrain = {m:map, k:key};  This is not sufficient to cause a leak in Fx9
     map.set(key, div);
     return make_weak_ref(map);
   };
 
   let weakref = make_gray_loop();
 
 
@@ -69,18 +75,25 @@ https://bugzilla.mozilla.org/show_bug.cg
     let dead_dom = document.createElement("div");
     let live_map = new WeakMap;
     let dead_map = new WeakMap;
     let live_key = {};
     let dead_key = {};
 
     // put the live/dead maps/keys into the appropriate DOM elements
     live_dom.basic_unit_tests = {m:live_map, k:live_key};
-    dead_dom.setUserData("hook", {m:dead_map, k:dead_key}, null);
+
+    let obj = {m:dead_map, k:dead_key};
     // dead_dom.hook = {m:dead_map, k:dead_key};
+    dead_dom.addEventListener("foo", function() {
+      // The code below doesn't matter (it won't run). Just pull a
+      // reference to obj.
+      obj.m = 1;
+      obj.k = "2";
+    });
 
     // Create a dead value, and a weak ref to it.
     // The loop keeps dead_dom alive unless the CC is smart enough to kill it.
     let dead_val = {loop:dead_dom};
     basic_weak_ref = make_weak_ref(dead_val);
     basic_map_weak_ref = make_weak_ref(dead_map);
 
     // set up the actual entries.  most will die.